Scrap несоответствующее количество пунктов, очищенных с помощью обратных вызовов и следующих ссылок - PullRequest
0 голосов
/ 17 февраля 2020

Я сканирую результаты желтых страниц и получаю непоследовательное количество очищенных элементов, когда пытаюсь перейти как к записям желтых страниц, так и к ссылкам на страницы. Я считаю, что у меня есть 2 проблемы, но я, кажется, могу обойти первую. Надеюсь, что это обходной путь не вызывает мою вторую проблему.

У меня нет проблем с получением 121 результатов поиска, которые я ожидаю от здесь . Я делаю это на основе этого примера из официального учебного пособия:

class LinksSpider(scrapy.Spider):
    name = "links"
    start_urls = [
        r"https://www.paginasamarillas.es/search/administrador-de-fincas/all-ma/zaragoza/all-is/zaragoza/all-ba/all-pu/all-nc/1?what=Administrador%20de%20fincas&where=Zaragoza",
    ]

    def parse(self, response):
        for comercial in response.css('div.col-xs-11.comercial-nombre .row a'):
            href = comercial.attrib["href"]
            if '#' not in href:
                print('href = ', href)
                yield {
                    'name': comercial.css('h2 span::text').get(),
                    'link': href,
                }

        list_items = response.css('ul.pagination li')
        for li in list_items:
            anchor = li.css('a')
            i = anchor.css('i')
            if len(i) != 0:
                next_page = anchor.attrib['href']
                print('next_page = ', next_page)

        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

Итак, моя первая проблема заключается в создании для l oop с list_items в качестве обходного пути к получить next_page. Это происходит потому, что кнопка, с помощью которой вы переходите на следующую страницу, отличается от li > a, как ярлыки для страниц 1, 2, ..., 5. Кнопка на следующей странице является единственной кнопкой с <i> внутри <a>. это li > a > i. В идеале я хотел бы сделать что-то вроде

for href in response.xpath('/html/body/div[5]/div[2]/div[1]/div[2]/div/div[4]/div[31]/ul/li[6]/a/i/../@href'):
    yield response.follow(href, self.parse) 

, но по какой-то причине div[5] не найден, хотя div[4] есть. Согласно моим исследованиям, потенциальной причиной может быть то, что 5-й div генерируется javascript и еще не существует к тому времени, когда паук получает html. Я сомневаюсь, что это реальная причина, потому что я могу видеть div, когда я сохраняю ответ в файл html. В любом случае, обходной путь правильно приводит к ожидаемым 121 элементам:

2020-02-17 17:37:07 [scrapy.core.engine] INFO: Closing spider (finished)
2020-02-17 17:37:07 [scrapy.extensions.feedexport] INFO: Stored json feed (121 items) in: links.json

Предполагая, что этот обходной путь не мешает моим следующим шагам, я согласен с ним и хотел бы сосредоточиться на своей второй проблеме. Чтобы следить за каждой желтой страницей и собирать информацию о каждой записи, я подражаю примеру в учебнике:

class FullSpider(scrapy.Spider):
    name = "full"
    start_urls = [
        r"https://www.paginasamarillas.es/search/administrador-de-fincas/all-ma/zaragoza/all-is/zaragoza/all-ba/all-pu/all-nc/1?what=Administrador%20de%20fincas&where=Zaragoza",
    ]

    def parse(self, response):
        for comercial in response.css('div.col-xs-11.comercial-nombre .row a'):
            href = comercial.attrib["href"]
            # sleep(1)
            if '#' not in href:
                print('href = ', href)
                yield response.follow(href, self.parse_comercial, meta={'link': href})

        list_items = response.css('ul.pagination li')
        for li in list_items:
            anchor = li.css('a')
            i = anchor.css('i')
            if len(i) != 0:
                next_page = anchor.attrib['href']
                print('next_page = ', next_page)

        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

    def parse_comercial(self, response):

        def extract_with_css(query):
            return response.css(query).get(default='').strip()

        yield {
            'name': extract_with_css('div.titular > h1::text'),
            'link': response.meta.get('link'),
            'sitioWeb': extract_with_css('div.botonesCta > a:not([id^="cfContacta"])::attr(href)'),
        }

Это дает почти точные результаты, которые я хочу, за исключением того, что вместо этого из 121 число возвращаемых элементов иногда составляет 91, иногда 94 и т. д. c.

2020-02-17 18:01:50 [scrapy.core.engine] INFO: Closing spider (finished)
2020-02-17 18:01:50 [scrapy.extensions.feedexport] INFO: Stored json feed (94 items) in: full.json

Мои исследования намекают на асинхронный характер этих запросов и / или выходов (две разные вещи, я знаете, но, может быть, один из них является виновником), но замедление (ie, добавление sleep()) или упрощение кода (с просьбой дать меньше ключей), похоже, не улучшат ситуацию.

Когда я набираю это, я замечаю скрап-статистику, ссылающуюся на фильтрацию дубликатов, но на самом деле я не могу понять эту статистику. Я дам их здесь, на случай, если это поможет кому-нибудь помочь.

После первого паука и правильных результатов 121:

2020-02-17 17:37:07 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 3167,
 'downloader/request_count': 5,
 'downloader/request_method_count/GET': 5,
 'downloader/response_bytes': 134605,
 'downloader/response_count': 5,
 'downloader/response_status_count/200': 5,
 'dupefilter/filtered': 1,
 'elapsed_time_seconds': 4.895525,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2020, 2, 17, 16, 37, 7, 343129),
 'item_scraped_count': 121,
 'log_count/DEBUG': 127,
 'log_count/INFO': 11,
 'request_depth_max': 5,
 'response_received_count': 5,
 'scheduler/dequeued': 5,
 'scheduler/dequeued/memory': 5,
 'scheduler/enqueued': 5,
 'scheduler/enqueued/memory': 5,
 'start_time': datetime.datetime(2020, 2, 17, 16, 37, 2, 447604)}

Второй паук, с противоречивыми результатами 90-94 :

2020-02-17 18:01:50 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 62095,
 'downloader/request_count': 99,
 'downloader/request_method_count/GET': 99,
 'downloader/response_bytes': 2154817,
 'downloader/response_count': 99,
 'downloader/response_status_count/200': 99,
 'dupefilter/filtered': 28,
 'elapsed_time_seconds': 9.433248,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2020, 2, 17, 17, 1, 50, 120636),
 'item_scraped_count': 94,
 'log_count/DEBUG': 194,
 'log_count/INFO': 11,
 'request_depth_max': 5,
 'response_received_count': 99,
 'scheduler/dequeued': 99,
 'scheduler/dequeued/memory': 99,
 'scheduler/enqueued': 99,
 'scheduler/enqueued/memory': 99,
 'start_time': datetime.datetime(2020, 2, 17, 17, 1, 40, 687388)}

Извините за длину, но я ценю любые советы. Спасибо!

РЕДАКТИРОВАТЬ: Первая проблема (обходной путь), кажется, решена благодаря @furas. Все еще борется со второй проблемой (противоречивые результаты), хотя.

1 Ответ

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

Чтобы получить ссылку на следующую страницу, вы можете выполнить поиск <a>, который имеет <i> с классом "fa icon-flecha-derecha", который отображает значок >. Могут быть и другие <i> со значком <, поэтому я должен использовать class для распознавания правильного значка.

Используя xpath, вы можете вкладывать элементы a[ i[@class="fa icon-flecha-derecha"] ], чтобы получить доступ к <a> <i> и получить @href

response.xpath('//ul[@class="pagination"]//li/a[i[@class="fa icon-flecha-derecha"]]/@href').get() #.getall()

Что касается 93 и 121.

Я сохранил URL-адреса в файле и использовал pandas для их сравнения.

Имеется 121 ссылка, но только 93 ссылки являются уникальными - некоторые из них повторяются на веб-страницах.

Первый код сохраняет все URL-адреса (даже повторные), второй код сохраняет только URL-адреса посещенных страниц - поскольку Scrapy больше не посещает ту же страницу, поэтому он посещает только 93 страницы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...