Scrapy: селектор для текста между двумя HTML элементами ..? - PullRequest
0 голосов
/ 15 февраля 2020

В настоящее время я использую скрап для очистки сайта. Сайт представляет собой список профилей. Таким образом, Паук нажимает на каждую ссылку в списке (то есть один профиль), а затем извлекает данные, возвращается и нажимает на следующую и т. Д. c. Вот как я это структурировал:

class Profiles(scrapy.Spider):
    name = 'profiles'
    allowed_domains = ['url.com']
    start_urls = ['https://www.url/profiles/']

    def parse(self, response):
        for profile in response.css('.herald-entry-content p'):
            url = response.urljoin(profile.css('a::attr(href)').extract_first())
            yield scrapy.Request(url=url, callback=self.parse_profile, dont_filter=True)

    def parse_profile(self, response):
        birth_name = response.xpath("//*[@id='post-19807']/div/div[1]/div/div[2]/div/p[1]/text()[1]").extract()
        profile = Profile(
            birth_name=birth_name
        )
        yield profile

Во время работы я столкнулся с проблемой при извлечении определенных данных. Вот фрагмент структуры на странице профиля:

    <div class="herald-entry-content">
        <p><b>Profile: Facts<br>
        </b><br>
            <span>Stage Name:</span> Any name<br>
            <span>Birth Name:</span> Any name<br>
            <span>Birthday:</span> July 10, 1994<br>
            <span>Zodiac Sign:</span> Cancer<br>
            <span>Height:</span> 178 cm <br>
        </p>
    </div>

Я бы хотел извлечь Birth Name здесь, но использование birth_name = response.css(".herald-entry-content p span::Text") даст мне текст элемента span что не то, что я хочу. Я попытался поиграться с xpath (правый клик и Copy Xpath в chrome), что дало мне //*[@id="post-19807"]/div/div[1]/div/div[2]/div/p[1]/text()[2] Теперь, это работает, но post-id указывает c на эту страницу, и я делаю l oop сверх другие профили, так что это значение сильно изменится. Можно ли как-то сказать пауку, чтобы он искал элемент и получил сам идентификатор? Я немного растерялся, как поступить с этим.

Большое спасибо!

1 Ответ

1 голос
/ 15 февраля 2020

Это может быть случай, когда вам нужно вернуться к регулярному выражению.

Не зная всей структуры страницы, трудно дать вам именно то, что вам нужно, но вот пример с использованием предоставленного вами фрагмента

import scrapy

sel = scrapy.Selector(text="""
 <div class="herald-entry-content">
        <p><b>Profile: Facts<br>
        </b><br>
            <span>Stage Name:</span> Any name<br>
            <span>Birth Name:</span> Any name<br>
            <span>Birthday:</span> July 10, 1994<br>
            <span>Zodiac Sign:</span> Cancer<br>
            <span>Height:</span> 178 cm <br>
        </p>
    </div>
""")

info = sel.re("<span>(.+):</span>\s(.+)<br>")
output = dict(zip(*[iter(info)] * 2))
print(output)

даст вам

{'Stage Name': 'Any name', 
 'Birth Name': 'Any name', 
 'Birthday': 'July 10, 1994', 
 'Zodiac Sign': 'Cancer', 
 'Height': '178 cm '}

Слегка крипт c dict(zip(*[iter(info)] * 2)) происходит от здесь .

Обратите внимание, что вам не нужно использовать scrapy.Selector напрямую, вы должны иметь возможность сделать что-то вроде

def parse_profile(self, response):
    herald_content = response.xpath('//div[@class="herald-entry-content"]')
    info = herald_content.re("<span>(.+):</span>\s(.+)<br>")
    # and so on from example above...
...