美文网首页虫虫
day73-scrapy框架使用

day73-scrapy框架使用

作者: barriers | 来源:发表于2019-02-27 19:59 被阅读49次

    1scrapy的使用

    1.1scrapy爬取数据流程

    scrapy由5个模块构成,分别是engine(引擎),spiders(爬虫),scheduler(调度),downloader(爬取),item pipelines(管道)
    Scrapy中的数据流由执⾏行行引擎控制,其过程如下: 1、引擎打开一个网站(open a domain),找到处理理该⽹网站的Spider并向该spider请求第一个要 爬取的URL(s)。 2、引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler)以Request调度。 3、引擎向调度器请求下一个要爬取的URL。 4、调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)⽅方向)转 发给下载器(Downloader)。 5、一旦⻚页⾯面下载完毕,下载器⽣生成⼀一个该⻚页⾯面的Response,并将其通过下载中间件(返回 (response)⽅方向)发送给引擎。 6、引擎从下载器中接收到Response并通过Spider中间件(输⼊入⽅方向)发送给Spider处理理。 7、Spider处理理Response并返回爬取到的Item及(跟进的)新的Request给引擎。 8、引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度 器。 9、(从第二步)重复直到调度器中没有更更多地request,引擎关闭该⽹网站。

    1.2scrapy安装

    linux中直接跳过windows安装过程中的一二步(见下)
    windows中需要安装其他插件;过程如下:
    1.进入http://www.lfd.uci.edu/~gohlke/pythonlibs/;搜索Twisted
    然后在cmd中输入python查看python版本及计算机为多少位(本次选择3.6版本64位);
    本次下载Twisted-18.9.0-cp36-cp36m-win_amd64.whl版本
    2.在cmd中进入存放虚拟环境的文件夹使用activate激活环境;然后退到存放第一步所下载的文件的文件夹。使用命令pip install Twisted-18.9.0-cp36-cp36m-win_amd64.whl将其安装到虚拟环境;
    3.安装pypiwin32 :pip install pypiwin32
    4.安装scrapy: pip install scrapy

    1.3创建项目及spider

    创建项目:命令行中输入scrapy startproject 项目名称
    如scrapy startproject sinanews
    进入项目后创建spider: 命令行中输入 scrapy genspider 名称 去掉http://的域名
    如scrapy genspider sport sports.sina.com.cn

    1.4配置项目

    打开项目后将settings中的ROBOTSTXT_OBEY = True改为ROBOTSTXT_OBEY = False;
    在最后添加编码格式:FEED_EXPORT_ENCODING = 'utf-8'
    运行spider文件:scrapy crawl sina -o result.json表示运行spider文件sina并将爬取数据存放到result.json文件中(会自动创建该文件),存放数据的类型有json、csv、xml及pickle
    scrapy crawl sina表示运行spider文件sina;但不将结果保存到本地。
    spider文件部分参数的作用
    allowed_domains: 允许爬取的域名;start_urls: Spider启动时爬取的url列表 ;parse: 负责解析返回的响应,提取数据或进一步处理理
    item文件的作用
    Item是保存爬取数据的容器

    2mysql使用

    python中的eval用法
    eval(字符串) 能将字符串当成程序运行
    mysql中清空数据库的两种方法及区别
    truncate table manhua清空数据库,若添加新数据id从1开始
    delete from manhau清空数据库,若添加新数据id将从之前的后面接着续

    3一个简单的scrapy项目-sinanews(get请求)

    spider文件中爬取数据

    import scrapy
    from sinanews.items import SinanewsItem        
    class SinaSpider(scrapy.Spider):
        name = 'sina'
        allowed_domains = ['sports.sina.com.cn']
        start_urls = ['http://sports.sina.com.cn/']    
        def parse(self, response):
            reult=response.selector.css('.ty-card-type10-makeup a::text').extract()
            for title in reult:
                item = SinanewsItem()
                item['title'] = title
                yield item
    

    items文件中保存数据

    import scrapy        
    class SinanewsItem(scrapy.Item):
        title = scrapy.Field()
    

    reult=response.selector.css('.ty-card-type10-makeup a::text').extract()该句表示获取class为该类型下的a标签中的text内容返回一个对象,后面接extract()表示获取其中的内容。

    4爬取虎扑网站数据(get请求)

    scrapy中处理数据用Selector选择器;其基于lxml构建,支持xpath, css, 正则表达式匹配

    import scrapy
    from hupu.items import HupuItem        
    class SproteSpider(scrapy.Spider):
        name = 'sprote'
        allowed_domains = ['bbs.hupu.com']
        start_urls = ['http://bbs.hupu.com/gear/']    
        # 构造请求
        def start_requests(self):
            headers = {
                'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
                'Accept': 'application/json, text/plain, */*',
                'Accept-Encoding': 'gzip, deflate, sdch',
                'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4,zh-TW;q=0.2,mt;q=0.2',
                'Connection': 'keep-alive',
                'X-Requested-With': 'XMLHttpRequest',
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            }
            for page in range(1, 101):
                yield scrapy.Request(url='http://bbs.hupu.com/gear-%d' % page,
                                     headers=headers,
                                     method='GET',
                                     callback=self.parse,
                                     )
    
        # 解析响应
        def parse(self, response):
            result_list = response.selector.css('.for-list li')
            for index in result_list:
                item = HupuItem()
                title = index.css('.truetit::text').extract_first()
                author = index.css('.aulink::text').extract_first()
                ti_date = index.css('.author.box').xpath('./a[2]/text()').extract_first()
                item['title'] = title
                item['author'] = author
                item['ti_date'] = ti_date
                yield item
    

    items中存取数据

    import scrapy        
    class HupuItem(scrapy.Item):
        title = scrapy.Field()
        author = scrapy.Field()
        ti_date = scrapy.Field()
    

    通过selector获取到对象后,仍然可以继续对其使用xpath,css,等选择器继续选择。
    result_list = response.selector.css('.for-list li')获取到result_list一个大的对象
    title = index.css('.truetit::text').extract_first()继续对其使用css选择器并获取获取到的第一个数据
    ti_date = index.css('.author.box').xpath('./a[2]/text()').extract_first()对其联合使用css选择器和xpath选择器
    result = response.css('.author.box').xpath('./a[2]/text()').re('(.?)-.?-')对其联合使用xpath,css及正则选择器

    5爬取有妖气网站(post请求)

    5.1爬取数据

    import json
    import re    
    import scrapy
    from u17.items import U17Item        
    class ComicSpider(scrapy.Spider):
        name = 'comic'
        allowed_domains = ['www.u17.com']
        start_urls = ['http://www.u17.com/']        
        def start_requests(self):
            headers = {
                'Referer': 'http://www.u17.com/comic/ajax.php?mod=comic_list&act=comic_list_new_fun&a=get_comic_list',
                'User-Agent': "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
                'Host': 'www.u17.com',
                'Accept': 'application/json, text/javascript, */*;',  # headers中requests headers中的accept数据
                'Accept-Encoding': 'gzip, deflate',
                'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4,zh-TW;q=0.2,mt;q=0.2',
                'Connection': 'keep-alive',
                'X-Requested-With': 'XMLHttpRequest',
            }
            url = 'http://www.u17.com/comic/ajax.php?mod=comic_list&act=comic_list_new_fun&a=get_comic_list'
            data = {'data[group_id]': 'no', 'data[theme_id]': 'no', 'data[is_vip]': 'no', 'data[accredit]': 'no',
                         'data[color]': 'no', 'data[comic_type]': 'no', 'data[series_status]': '1', 'data[order]': '1',
                         'data[page_num]': '1', 'data[read_mode]': 'no'
                         }
            for page in range(5):
                data['data[page_num]'] = str(page)
                print(page)
                yield scrapy.FormRequest(url=url,
                                     headers=headers,
                                     method='POST',
                                     formdata=data,
                                     callback=self.parse,
                                     )    
        def parse(self, response):
            result=json.loads(response.text)
            result_list = result['comic_list']
            pattern = re.compile('<font.*?>(.*?)<.*?', re.S)
            for item in result_list:
                u17_item = U17Item()
                u17_item['comic_id'] = item['comic_id']
                u17_item['name'] = item['name']
                u17_item['cover'] = item['cover']
                u17_item['category'] = re.findall(pattern, item['line2'])[0]
                yield u17_item
    

    注意:在循环提交请求的网页数据时;需将Request改为FormRequest;method改为POST
    items中保存数据

    import scrapy       
    class U17Item(scrapy.Item):
        comic_id = scrapy.Field()
        name = scrapy.Field()
        cover = scrapy.Field()
        category = scrapy.Field()
    

    该文件中保存数据的字段必须与spider文件中给对象添加属性的字段保持一致。
    然后在settings文件中修改ROBOTSTXT_OBEY为False;添加编码方式FEED_EXPORT_ENCODING = 'utf-8'。

    5.2保存数据

    数据保存在管道(pipelines)中进行

    5.2.1mysql中保存数据

    import pymysql
    import pymongo    
    from scrapy import Request
    from scrapy.exceptions import DropItem
    from scrapy.pipelines.images import ImagesPipeline
    class U17MysqlPipeline(object):
        def __init__(self, host, port, username, password, database):
            self.host = host
            self.port = port
            self.username = username
            self.password = password
            self.database = database    
        @classmethod
        def from_crawler(cls, crawler):
            return cls(
                host=crawler.settings.get('MYSQL_HOST'),
                port=crawler.settings.get('MYSQL_PORT'),
                database=crawler.settings.get('MYSQL_DATABASE'),
                username=crawler.settings.get('MYSQL_USERNAME'),
                password=crawler.settings.get('MYSQL_PASSWORD'),
            )    
        def open_spider(self, spider):
            self.db = pymysql.connect(self.host, self.username, 
                  self.password, self.database, charset='utf8',
                                      port=self.port)
            self.cursor = self.db.cursor()        
        def close_spider(self, spider):
            self.db.close()    
        def process_item(self, item, spider):
            sql = 'insert into manhua (comic_id, name, cover, category) 
                values (%s,%s,%s,%s)'
            self.cursor.execute(sql, (item['comic_id'], item['name'], 
                item['cover'], item['category']))
            self.db.commit()
            return item
    

    5.2.2mongodb中保存数据

    class U17MongoPipeline(object):
        def __init__(self, uri, database):
            self.uri = uri
            self.database = database    
        @classmethod
        def from_crawler(cls, crawler):
            return cls(
                uri=crawler.settings.get('MONGO_URI'),
                database=crawler.settings.get('MONGO_DB'),
            )    
        def open_spider(self, spider):
            self.client = pymongo.MongoClient(self.uri)
            self.db = self.client[self.database]        
        def close_spider(self, spider):
            self.client.close()        
        def process_item(self, item, spider):
            self.db['manhua'].insert(dict(item))
            return item
    

    5.2.3下载图片

    class U17ImagePipeline(ImagesPipeline):
        # 准备图片文件名
        def file_path(self, request, response=None, info=None):
            url = request.url
            file_name = url.split('/')[-1]
            return file_name
        # 判断图片是否下载成功,丢弃不成功的
        def item_completed(self, results, item, info):
            image_paths = [x['path'] for ok, x in results if ok]
            if not image_paths:
                raise DropItem('Image Downloaded Failed')
            return item    
        # 指明图片下载链接,并包装成request对象
        def get_media_requests(self, item, info):
            yield Request(item['cover'])
    

    5.2.4保存路径的配置

    将上面定义的三个保存数据的类添加到settings中的ITEM_PIPELINES中(68行处)

    ITEM_PIPELINES = {
    # 前面是管道,后面是优先级,数值越小,优先级越高
    'u17.pipelines.U17MysqlPipeline': 300,
    'u17.pipelines.U17MongoPipeline': 320,
    'u17.pipelines.U17ImagePipeline': 340,
    }
    

    'u17.pipelines.U17MysqlPipeline': 300, 前面是管道,后面是优先级,数值越小,优先级越高。将上面定义的保存数据的类添加到此处,运行spider文件,则会自动保存文件到对应的路径;当不需要保存到某个数据库时,在此处注释对应的方法就可以。
    然后在最末行添加下面语句
    在添加图片路径前,需要先在工程目录下创建images文件夹

     # 配置图片目录
     IMAGES_STORE = './images'      
     # mysql 设置
     MYSQL_HOST = '127.0.0.1'
     MYSQL_PORT = 3306
     MYSQL_USERNAME = 'root'
     MYSQL_PASSWORD = '123456'
     MYSQL_DATABASE = 'u17'      
     # MONGO 配置
     MONGO_URI = 'mongodb://127.0.0.1:27017'
     MONGO_DB = 'u17'
    

    相关文章

      网友评论

        本文标题:day73-scrapy框架使用

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