2012-10-11 98 views
21

我有以下形式的网址:scrapy - 这是分页解析项目

example.com/foo/bar/page_1.html 

总共有53页是,他们每个人都有〜20行。

我基本上想要从所有页面获取所有行,即〜53 * 20个项目。

我在parse方法工作的代码,它分析一个网页,并且还进入每个项目一个页面更深,以获取有关该项目的详细信息:

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 

回答

33

你有两个选择来解决你的问题。一般是使用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)] 
+0

start_urls想法很棒。非常感谢 – AlexBrand

+0

优秀的答案。非常感谢。 scrapy网站上的LinkExtractor并不适合我。这样做。 –

+0

如何检查页面是否找不到。它只有53页。但如果我叫'xrange(1,60)'。 – user1586957

11

您可以使用CrawlSpider代替BaseSpider和使用SgmlLinkExtractor提取的网页:刚刚从这样的图案产生开始URS名单在分页。

例如:

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

+0

我遇到了类似的问题,我所做的就像你说的,但它仍然只是抓取start_url页面。 –

+0

SgmlLinkExtractors和contrib模块中的所有其他类都会引发错误。请改用LinkExtracor类。 –

6

可以有两个用例的“scrapy - 这是分页解析项目”。 A)

A)。我们只是想在表格中移动并获取数据。这是相对直接的。

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行。这里

  1. 我们从'下一步'分页按钮获得下一页链接表单下一页xpath。
  2. 如果检查条件是否不是分页结束。
  3. 加入此链接(我们得到了第1步)与主要URL使用url加入
  4. 递归调用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''' 

Overhere,观察到:

  1. 我们使用CrawlSpider

  2. 我们已经设置为scrapy.Spider父类的 '规则'

    一)第一条规则,只是检查是否有'next_page'可用并且遵循它。

    b)第二个规则请求页面上所有格式为/trains/12343的链接,然后调用parse_trains来执行和解析操作。

  3. 重要:请注意,我们不希望在这里使用常规parse方法,我们使用CrawlSpider子类。该课程还有一个parse方法,因此我们不希望覆盖该方法。只要记住将您的回拨方式命名为parse以外的方法即可。