Подтвердить что ты не робот

Scrapy - парсинг элементов, разбитых на страницы

У меня есть url формы:

example.com/foo/bar/page_1.html

В общей сложности 53 страницы, каждая из которых имеет ~ 20 строк.

Я в основном хочу получить все строки со всех страниц, т.е. ~ 53 * 20 элементов.

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

  def parse(self, response):
    hxs = HtmlXPathSelector(response)

    restaurants = hxs.select('//*[@id="contenido-resbus"]/table/tr[position()>1]')

    for rest in restaurants:
      item = DegustaItem()
      item['name'] = rest.select('td[2]/a/b/text()').extract()[0]
      # some items don't have category associated with them
      try:
        item['category'] = rest.select('td[3]/a/text()').extract()[0]
      except:
        item['category'] = ''
      item['urbanization'] = rest.select('td[4]/a/text()').extract()[0]

      # get profile url
      rel_url = rest.select('td[2]/a/@href').extract()[0]
      # join with base url since profile url is relative
      base_url = get_base_url(response)
      follow = urljoin_rfc(base_url,rel_url)

      request = Request(follow, callback = parse_profile)
      request.meta['item'] = item
      return request


  def parse_profile(self, response):
    item = response.meta['item']
    # item['address'] = figure out xpath
    return item

Вопрос в том, как я сканирую каждую страницу?

example.com/foo/bar/page_1.html
example.com/foo/bar/page_2.html
example.com/foo/bar/page_3.html
...
...
...
example.com/foo/bar/page_53.html
4b9b3361

Ответ 1

У вас есть два варианта решения вашей проблемы. Общее состоит в том, чтобы использовать yield для генерации новых запросов вместо return. Таким образом, вы можете выдать более одного нового запроса из одного обратного вызова. Проверьте второй пример на http://doc.scrapy.org/en/latest/topics/spiders.html#basespider-example.

В вашем случае есть, вероятно, более простое решение: просто сгенерируйте список стартовых устройств из такого типа:

class MySpider(BaseSpider):
    start_urls = ['http://example.com/foo/bar/page_%s.html' % page for page in xrange(1,54)]

Ответ 2

Вы можете использовать CrawlSpider вместо BaseSpider и использовать SgmlLinkExtractor для извлечения страниц в разбивке на страницы.

Например:

start_urls = ["www.example.com/page1"]
rules = ( Rule (SgmlLinkExtractor(restrict_xpaths=('//a[@class="next_page"]',))
                , follow= True),
          Rule (SgmlLinkExtractor(restrict_xpaths=('//div[@class="foto_imovel"]',))
                , callback='parse_call')
    )

Первое правило сообщает, что scrapy следует за ссылкой, содержащейся в выражении xpath, второе правило сообщает scrapy о вызове parse_call для ссылок, содержащихся в выражении xpath, в случае, если вы хотите разобрать что-то на каждой странице.

Для получения дополнительной информации см. документ: http://doc.scrapy.org/en/latest/topics/spiders.html#crawlspider

Ответ 3

Для "scrapy - парсинга элементов, разбитых на страницы" могут быть два варианта использования.

А). Мы просто хотим переместиться через таблицу и получить данные. Это относительно прямо.

class TrainSpider(scrapy.Spider):
    name = "trip"
    start_urls = ['somewebsite']
    def parse(self, response):
        ''' do something with this parser '''
        next_page = response.xpath("//a[@class='next_page']/@href").extract_first()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

Наблюдайте последние 4 строки. Здесь

  • Мы получаем следующую ссылку на страницу следующей страницы xpath из кнопки "Следующая".
  • если условие, чтобы проверить, не является ли его окончанием разбивки на страницы.
  • Присоединитесь к этой ссылке (которую мы получили на шаге 1) с основным URL-адресом, используя URL-соединение.
  • Рекурсивный вызов метода обратного вызова parse.

B) Мы не только хотим перемещаться по страницам, но также хотим извлечь данные из одной или нескольких ссылок на этой странице.

class StationDetailSpider(CrawlSpider):
    name = 'train'
    start_urls = [someOtherWebsite]
    rules = (
        Rule(LinkExtractor(restrict_xpaths="//a[@class='next_page']"), follow=True),
        Rule(LinkExtractor(allow=r"/trains/\d+$"), callback='parse_trains')
    )
    def parse_trains(self, response):
    '''do your parsing here'''

Проследите, чтобы:

  • Мы используем подкласс CrawlSpider родительского класса scrapy.Spider

  • Мы установили "Правила"

    a) Первое правило просто проверяет наличие "следующей_страницы" и следует за ним.

    b) Второе правило запрашивает все ссылки на странице, находящиеся в формате, например /trains/12343, а затем вызывает parse_trains для выполнения и синтаксического анализа.

  • Важно. Обратите внимание: мы не хотим использовать обычный parse метод здесь, поскольку мы используем подкласс CrawlSpider. Этот класс также имеет метод parse, поэтому мы не хотим его переопределять. Просто не забудьте назвать свой метод обратного вызова чем-то другим, кроме parse.