2012-10-11 12 views
21

que tienen una dirección URL de la forma:Scrapy - análisis de los artículos que están paginados

example.com/foo/bar/page_1.html 

Hay un total de 53 páginas, cada una de ellas tiene ~ 20 filas.

Básicamente quiero obtener todas las filas de todas las páginas, es decir ~ 53 * 20 elementos.

código He trabajando en mi método de análisis, que analiza una sola página, y también va una página más profundo por artículo, para obtener más información sobre el artículo:

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 

La pregunta es, ¿cómo puedo rastrear cada página?

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 

Respuesta

33

Tiene dos opciones para resolver su problema. El general es usar yield para generar nuevas solicitudes en lugar de return. De esta forma, puede emitir más de una solicitud nueva desde una única devolución de llamada. Verifique el segundo ejemplo al http://doc.scrapy.org/en/latest/topics/spiders.html#basespider-example.

En su caso no es probablemente una solución más simple: Sólo generar la lista de urs parten de un golpeteo de la siguiente manera:

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

start_urls idea is great. muchas gracias – AlexBrand

+0

Excelente respuesta. Muchas gracias por esto. El LinkExtractor en el sitio de scrapy no funcionó para mí. Esto hizo. –

+0

cómo comprobar si no se encuentra la página. solo tiene 53 páginas. pero si llamo 'xrange (1,60)'. – user1586957

11

Se podría utilizar el CrawlSpider en lugar de la BaseSpider y utilizar SgmlLinkExtractor para extraer las páginas en la paginación

Por ejemplo:

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') 
    ) 

La primera regla dice scrapy para seguir el enlace que figura en la expresión XPath, la segunda regla dice scrapy a llamar a la parse_call a los enlaces contenidos en la expresión XPath, en caso de que quiera para analizar algo en cada página.

Para obtener más información consulte el documento: http://doc.scrapy.org/en/latest/topics/spiders.html#crawlspider

+0

Encontré un problema similar, lo que hice fue lo que dijiste, y aún así solo rastreó la página start_url. –

+0

SgmlLinkExtractors y todas las demás clases en el módulo contrib provocan errores. Utilice la clase LinkExtracor en su lugar. –

6

No puede haber dos casos de uso para Scrapy '- análisis de los artículos que están paginados.

A). Solo queremos movernos por la mesa y buscar datos. Esto es relativamente sencillo.

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) 

Observe las últimas 4 líneas. Aquí

  1. Estamos obteniendo el siguiente enlace a la página siguiente página xpath desde el botón 'Siguiente' de paginación.
  2. si condición para comprobar si no es el final de la paginación.
  3. Unirse a este enlace (que obtuvimos en el paso 1) con la url principal mediante url join
  4. Llamada recursiva al método de devolución de llamada parse.

B) No solo queremos movernos por las páginas, sino que también queremos extraer datos de uno o más enlaces en esa página.

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''' 

overhere, observar que:

  1. Estamos utilizando el CrawlSpider subclase de la clase scrapy.Spider padres

  2. Hemos establecido a 'Reglas'

    a) La primera regla, simplemente verifica si hay una 'página siguiente' disponible y la sigue.

    b) La segunda regla solicita todos los enlaces en una página que están en el formato, digamos /trains/12343 y luego llama al parse_trains para realizar y analizar la operación.

  3. Importante: Tenga en cuenta que no queremos usar el método regular parse aquí como estamos usando CrawlSpider subclase. Esta clase también tiene un método parse, por lo que no queremos anularlo. Recuerde recordar el nombre de su método de devolución de llamada, que no sea parse.

Cuestiones relacionadas