web使用scrapy抓取和提取数据

时间:2017-03-14 04:51:18

标签: python-2.7 web-scraping scrapy web-crawler scrapy-spider

我是蟒蛇和scrapy的新手。 我正在尝试抓取种子网址https://www.health.com/patients/status/.This种子网址包含许多网址。但我想从种子网址中仅获取包含Faci / Details /#somenumber的网址。网址如下:

https://www.health.com/patients/status/ ->https://www.health.com/Faci/Details/2                                                                                                        
                                   -> https://www.health.com/Faci/Details/3
                                   -> https://www.health.com/Faci/Details/4



https://www.health.com/Faci/Details/2 -> https://www.health.com/provi/details/64
                                 -> https://www.health.com/provi/details/65


https://www.health.com/Faci/Details/3 -> https://www.health.com/provi/details/70
                                 -> https://www.health.com/provi/details/71

在每个https://www.health.com/Faci/Details/2页面内https://www.health.com/provi/details/64 https://www.health.com/provi/details/65 ...最后我想从中获取一些数据 https://www.health.com/provi/details/#somenumber url。我怎样才能达到同样的目标?

截至目前,我已经尝试了scrapy教程中的以下代码,并且只能抓取包含https://www.health.com/Faci/Details/#somenumber的网址。它不会转到https://www.health.com/provi/details/#somenumber。我试图在settings.py文件中设置深度限制但它没有用。

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from news.items import NewsItem


class MySpider(CrawlSpider):
name = 'provdetails.com'
allowed_domains = ['health.com']
start_urls = ['https://www.health.com/patients/status/']

rules = (

  Rule(LinkExtractor(allow=('/Faci/Details/\d+', )),  follow=True),

  Rule(LinkExtractor(allow=('/provi/details/\d+', )),callback='parse_item'),                  
)

def parse_item(self, response):
    self.logger.info('Hi, this is an item page! %s', response.url)
    item = NewsItem()
    item['id'] = response.xpath("//title/text()").extract()
    item['name'] = response.xpath("//title/text()").extract()
    item['description'] = response.css('p.introduction::text').extract()
    filename='details.txt'
    with open(filename, 'wb') as f:
        f.write(item)
    self.log('Saved file %s' % filename)
    return item

请帮我继续深造?

1 个答案:

答案 0 :(得分:1)

说实话,基于正则表达式和强大的Rule/LinkExtractor给了我很多时间。对于简单项目,它可能是一种在页面上提取所有链接然后查看href属性的方法。如果href符合您的需求,yield一个新的Response对象。例如:

 from scrapy.http import Request
 from scrapy.selector import Selector
...
    # follow links
    for href in sel.xpath('//div[@class="contentLeft"]//div[@class="pageNavigation nobr"]//a').extract():
            linktext = Selector(text=href).xpath('//a/text()').extract_first()
            if linktext and linktext[0] == "Weiter":
                    link = Selector(text=href).xpath('//a/@href').extract()[0]
                    url = response.urljoin(link)
                    print url
                    yield Request(url, callback=self.parse)

对您的代码的一些评论:

    response.xpath(...).extract() 

这将返回一个列表,您可能希望查看提供第一项(或None)的extract_first()

    with open(filename, 'wb') as f:

这将多次覆盖该文件。您只能获得最后保存的项目。您也可以以二进制模式('b')打开文件。从文件名,我想你想把它作为文本阅读?使用'a'追加?见open() docs 另一种方法是使用-o flag来使用scrapys工具将项目存储为JSON或CSV。

    return item

这是yield项目的好方式,而不是返回它们。至少如果您需要从一个页面创建多个项目,则需要yield

另一个好方法是:对一种类型/种类的页面使用一个parse()函数

例如,start_urls中的每个页面都填入parse()。通过该提取,您可以使用回调yield为每个Request页面提取链接和/Faci/Details/N parse_faci_details()。在parse_faci_details()中,您再次提取感兴趣的链接,创建Request并通过callback=将其传递给parse_provi_details()。 在此功能中,您可以创建所需的项目。