二. Scrapy常用函数及方法

作者: 橄榄的世界 | 来源:发表于2018-03-05 08:54 被阅读0次

    1.spider开发流程:

    • 最简单的Spider只需4个步骤:
      1).继承scrapy.Spider;
      2).为Spider取名;
      3).设置爬取的起始点;
      4).实现页面解析函数。

    其中,Spider是一个基类,后面我们使用到的所有其他爬虫都需要继承这个Spider基类,例如:CrawlSpider,XMLFeedSpider,CSVFeedSpider,SitemapSpider等,这些类全部位于scrapy\spiders目录之下。

    实际上设置完爬取起始点后,默认由start_reqeusts()方法构建Request对象,然后默认指定由parse方法作为页面解析函数。如果我们希望为Request添加特定的请求头部或想为Request指定特定的页面解析函数,可以考虑在构建的Spider类中实现start_requests方法,即可覆盖基类Spider的start_requests方法。例如,在第一章的基础上进行修改:

    import scrapy
    
    class Books(scrapy.Spider):
        name = 'books'
        #start_urls = ['http://books.toscrape.com/']
    
        #实现start_requests方法,替代start_urls这个类属性
        def start_requests(self):
            yield scrapy.Request(url="http://books.toscrape.com/",
                                 callback=self.parse_book,    #此时改用parse_book作为回调函数
                                 headers={'User-Agent':'Mozilla/5.0'},
                                 dont_filter=True)
    
        def parse_book(self,response):
            infos = response.xpath('//article')
            for info in infos:
                title = info.xpath("h3/a/@title").extract()[0]
                price = info.xpath('div/p[@class="price_color"]/text()').extract()[0]
    
                yield {'title': title, 'price': price}   
    

    所以,设置爬取的起爬点有两种方法:

    • 定义start_urls属性
    • 改写start_requests方法

    而第四个步骤,页面解析函数需要完成以下两个工作:
    1).提取数据,将数据封装后(Item或字典)提交给Scrapy引擎;
    2).提取链接,并用链接构造新的Request对象提交给Scrapy引擎;其中,提取链接的方法包括使用选择器或使用LinkExtractor。

    2.常用方法

    1)提取常用方法
    .extract() 对结果以列表的形式进行返回
    .extract_first() 对extract()返回的结果列表取第一个元素。
    .re() #对结果使用正则表达式进行再提取
    .re_first() #返回第一个re()结果。

    2)调用selector的方法
    selector类的实现位于scrapy.selector模块,通过创建对象即可使用css或xpath解析方法。

    from scrapy.selector import Selector
    
    class Book(scrapy.Spider):
        ...
        
        def parse(self,response):
            selector = Selector(response)
            infos = selector.xpath("//h1")
            ...
    

    当然,实际开发中,我们无需创建Selector对象,因为当我们第一次访问Response对象的selector属性时,Response对象会自动创建Selector对象,同时在Response对象中内置了selector对象的css和xpath方法以供使用。

    class Book(scrapy.Spider):
        ...
    
        def parse(self,response):
            infos = response.xpath("//h1")
    

    3)使用Item封装数据(items.py)
    相对于使用字典来维护数据信息,使用item封装数据,有以下好处:
    ①清楚了解数据中包含哪些字段;
    ②包含对字段名字的检测;
    ③方便携带元数据,用于传递给其他组件的信息;

    • 数据段的基类:Item基类
    • 描述数据包含哪些字段的类:FIeld类
      在items.py中这样写:
    from scrapy import Item,Field
    
    class BooksItem(Item):
        title = Field()
        price = Field()
    

    在project为books,spiders文件夹下的books.py下这样写:

    from books.items import BooksItem     #引入items.py中创建的对象
        def parse_book(self,response):
            infos = response.xpath('//article')
            book = BooksItem()   #实例化BooksItem()
            for info in infos:
                book['title'] = info.xpath("h3/a/@title").extract()[0]
                book['price'] = info.xpath('div/p[@class="price_color"]/text()').extract()[0]
    
                yield book      #返回book
    

    4)使用Item Pipeline处理数据(pipelines.py)
    Item Pipeline的几种典型应用:

    • 清洗数据
    • 验证数据的有效性
    • 过滤重复的数据
    • 将数据存入数据库

    ①Item Pipeline不需要继承特定基类,只需要实现特定方法,例如:process_item、open_spider、close_spider。
    ②一个Item Pipeline必须实现一个process_item(item,spider)方法,该方法用来处理每一项由Spider爬取到的数据,其中两个参数:
    item: 爬取到的一项数据(Item或字典)
    spider:爬取此项数据的Spider对象
    例如将Sharp Objects,£47.82中的英镑转换成人民币Sharp Objects,¥406.47
    代码为:

    class PriceConverterPipeline(object):
        
        exchange_rate = 8.5  #英镑对人民币汇率
        
        def process_item(self, item, spider):
            price = item['price'][1:] * self.exchange_rate
            item['price'] = price
            
            return item
    

    写入MongoDB的代码,方式一:

    import pymongo
    
    class MongoDBPipeline(object):
        def __init__(self):
            client = pymongo.MongoClient('localhost',27017)
            test = client['test']
            book = test['book']
            self.post = book
            
        def process_item(self,item,spider):
            info = dict(item)
            self.post.insert(info)
            return item
    

    写入MongoDB的代码,方式二:

    import pymongo
    
    class MongoDBPipeline(object):
        DB_URI = 'mongodb://localhost:27017/'
        DB_NAME = 'test'
        
        def open_spider(self,spider):
            self.client = pymongo.MongoClient(self.DB_URI)
            self.db = self.client[self.DB_NAME]
            
        def close_spider(self,spider):
            self.client.close()
    
        def process_item(self, item, spider):
            collection = self.db['book']
            post = dict(item)
            collection.insert_one(post)
            return item
    

    过滤重复数据,这里以书名作为主键判断重复项,实际上应该以ISBN编号为主键,只是前面仅爬取了书名和价格。

    from scrapy.exceptions import DropItem
    
    class DuplicatesPipeline(object):
        def __init__(self):
            self.book_set = set()
            
        def process_item(self,item,spider):
            name = item['name']
            if name in self.book_set:
                raise DropItem('Duplicate book found:%s' %item)
            self.book_set.add(name)
            return item
    

    由于Item Pipeline是可选的组件,想要启用某个Item Pipeline,需要在settings.py中可对Item Pipeline进行设置。
    例如:

    ITEM_PIPELINES = {
       'books.pipelines.PriceConverterPipeline': 300,
       'books.pipelines.MongoDBPipeline': 500,
       'books.pipelines.DuplicatesPipeline': 400,
    }
    

    其中,字典中的key为导入路径,后面的value是0~1000的数字。如果同时启动多个Pipeline,优先处理数字最小的Pipeline。

    5)使用LinkExtractor提取链接
    提取链接信息有两种方法,简单少量的链接使用Selector就足够了,而对于大量的链接或者复杂规则的链接,使用LinkExtractor更方便。
    下面是代码的比较:

    • Selector()
    next_url = response.xpath('//li[@class="next"]/a/@href').extract()[0]
    if next_url:
        next_url = response.urljoin(next_url)
        yield scrapy.Request(next_url,callback=self.parse)
    
    • LinkExtractor()
    from scrapy.linkextractors import LinkExtractor
    next = LinkExtractor(restrict_xpaths='//li[@class="next"]')  #LinkExtractor中添加限制条件,如果为空会提取页面的所有链接
    links = next.extract_links(response)  #返回一个Link对象的列表,里面包含链接。
    if links:
        next_url = links[0].url   #next_url[0]可获取Link对象,Link对象的url属性就是绝对地址,无需自己构建相对地址。
        yield scrapy.Request(next_url,callback=self.parse)
    

    6)使用Exporter导出数据(settings.py)

    • 可以使用命令行参数指定
    • 通过配置文件指定

    命令行: scrapy crawl -o books.csv
    scrapy crawl -o books.csv -t csv ## -t可以省略

    配置文件:

    选项 含义 示例
    FEED_URI 导出文件路径 FEED_URI = 'books.csv'
    FEED_FORMAT 导出数据格式 FEED_FORMAT = 'csv'
    FEED_EXPORT_ENCODING 导出文件编码方式 FEED_EXPORT_ENCODING='gbk'
    FEED_EXPORT_FIELDS 指定导出哪些字段并排序 FEED_EXPORT_FIELDS={'title','price'}
    FEED_EXPORTERS 用户自定义Exporter字典,一般用于添加新的导出数据格式 FEED_EXPORTERS ={‘excel’:'项目名.新设置的py文件名.ExcelItemExporter'}

    相关文章

      网友评论

        本文标题:二. Scrapy常用函数及方法

        本文链接:https://www.haomeiwen.com/subject/cpvffftx.html