Я сканирую результаты желтых страниц и получаю непоследовательное количество очищенных элементов, когда пытаюсь перейти как к записям желтых страниц, так и к ссылкам на страницы. Я считаю, что у меня есть 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. Все еще борется со второй проблемой (противоречивые результаты), хотя.