2012-10-11 7 views
21

Mam URL w postaci:scrapy - analizowania elementów, które są paginowane

example.com/foo/bar/page_1.html 

Istnieje w sumie 53 stron, każda z nich ma ~ 20 wierszy.

Zasadniczo chcę uzyskać wszystkie wiersze ze wszystkich stron, tj. ~ 53 * 20 pozycji.

Mam kod działa w moim metody parse, że analizuje jedną stronę, a także przechodzi jedna strona głębiej za sztukę, aby uzyskać więcej informacji na temat urządzenia:

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 

Pytanie brzmi, jak mogę przeszukiwać każdą stronę?

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 

Odpowiedz

33

Masz dwie opcje rozwiązania problemu. Ogólny polega na użyciu yield do generowania nowych żądań zamiast return. W ten sposób możesz wydać więcej niż jedno nowe żądanie z jednego wywołania zwrotnego. Sprawdź drugi przykład pod adresem http://doc.scrapy.org/en/latest/topics/spiders.html#basespider-example.

W twoim przypadku prawdopodobnie jest to prostsze rozwiązanie: Wystarczy wygenerować listę Urs zacząć od tupot jak ten:

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

pomysł start_urls jest świetny. wielkie dzięki – AlexBrand

+0

Doskonała odpowiedź. Dziękuję za to. LinkExtractor na stronie scrapy nie działa dla mnie. Tak było. –

+0

jak sprawdzić, czy strona nie została znaleziona. ma tylko 53 strony. ale jeśli nazywam 'xrange (1,60)'. – user1586957

11

można użyć CrawlSpider zamiast BaseSpider i wykorzystać SgmlLinkExtractor wyodrębnić stron w paginacji.

Na przykład:

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

Pierwsza zasada mówi scrapy w link zawarty w wyrażeniu XPath, druga zasada mówi scrapy wezwać parse_call do linków zawartych w wyrażeniu XPath, w przypadku, gdy chcesz parsować coś na każdej stronie.

Aby uzyskać więcej informacji proszę zobaczyć Doc: http://doc.scrapy.org/en/latest/topics/spiders.html#crawlspider

+0

Mam podobny problem, co zrobiłem, jak powiedziałeś, a mimo to nadal indeksuje tylko stronę start_url. –

+0

SgmlLinkExtractors i wszystkie inne klasy w module contrib wywołują błędy. Zamiast tego należy użyć klasy LinkExtracor. –

6

Nie może być dwa przypadki wyrażeniem 'scrapy - analizowania elementów, które są podzielone na strony.

A). Chcemy po prostu przejść przez stół i pobrać dane. Jest to stosunkowo proste.

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) 

Obserwuj ostatnie 4 linie. Tutaj

  1. Otrzymujemy następny link do strony z następną stroną xpath z przycisku "Dalej".
  2. jeśli warunek sprawdzenia, czy nie jest to koniec paginacji.
  3. Dołącz do tego linka (otrzymaliśmy w kroku 1) za pomocą głównego adresu URL, używając adresu URL:
  4. Rekurencyjne wywołanie metody odwołań parse.

B) Nie tylko chcemy poruszać się po stronach, ale także chcemy wyodrębnić dane z jednego lub więcej linków na tej stronie.

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, zauważają, że:

  1. Używamy CrawlSpider podklasę klasy scrapy.Spider dominującej

  2. Mamy ustawiony na 'Rules'

    a) Pierwsza zasada, sprawdza, czy dostępna jest "następna strona" i podąża za nią.

    b) Druga reguła żąda wszystkich linków na stronie w formacie, na przykład /trains/12343, a następnie wywołuje parse_trains, aby wykonać i przetworzyć operację.

  3. Ważne: Zauważ, że nie chcemy korzystać z regularną metodę parse tu jak używamy CrawlSpider podklasy. Ta klasa ma również metodę parse, więc nie chcemy tego przesłonić. Po prostu pamiętaj, aby nadać swojej metodzie odwołanie coś innego niż parse.

Powiązane problemy