热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

爬虫05/scrapy框架

目录爬虫06scrapy框架1.scrapy概述安装2.基本使用3.全栈数据的爬取4.五大核心组件对象5.适当提升scrapy爬取数据的效率6.请求传参爬虫06scrapy框架1.

目录



  • 爬虫06 /scrapy框架

    • 1. scrapy概述/安装

    • 2. 基本使用

    • 3. 全栈数据的爬取

    • 4. 五大核心组件/对象

    • 5. 适当提升scrapy爬取数据的效率

    • 6. 请求传参



爬虫06 /scrapy框架


1. scrapy概述/安装



  • 异步的爬虫框架



    • 高性能的数据解析,持久化存储,全栈数据的爬取,中间件,分布式

    • Twisted:就是scrapy的异步机制


  • 框架:就是一个集成好了各种功能且具有很强通用性的一个项目模板。


  • 环境安装:

    Linux:

    pip3 install scrapy

    Windows:

    a. pip3 install wheel
    b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
    c. 进入下载目录,执行 pip3 install Twisted-18.9.0-cp36-cp36m-win_amd64.whl
    d. pip3 install pywin32
    e. pip3 install scrapy



2. 基本使用


1. 创建工程



  1. 新建一个工程:scrapy startproject proName



    • settings.py:当前工程的配置文件

    • spiders:爬虫包,必须要存放一个或者多个爬虫文件(.py)


  2. 切换到工程目录:cd proName


  3. 创建一个爬虫文件:scrapy genspider spiderName www.lbzhk.com


  4. 执行工程:scrapy crawl spiderName(爬虫文件名)

    settings.py:(一般在创建工程后,先在settings中作如下设置)



    1. 不遵从robots协议

    2. UA伪装

    3. 指定日志输出的类型:LOG_LEVEL = 'ERROR'

    # 设置请求头USER_AGENT
    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    # 是否遵循robots协议
    ROBOTSTXT_OBEY = False
    # 记录日志的等级
    LOG_LEVEL = 'ERROR'



2. 数据分析



  • response.xpath('xpath表达式')


  • scrapy中的xpath解析,在进行数据提取的时候,xpath方法返回的列表中存储的不再是字符串,而是存储的Selector对象,相关的字符串数据是存储在Selector对象的data参数中,我们必须使用


  • extract()/extract_first()进行字符串数据的提取

    extract():可以作用到列表中的每一个列表元素中,返回的依然是一个列表

    extract_first():只可以作用到列表中的第一个列表元素中,返回的是字符串



3. 持久化存储



  • 基于终端指令的持久化存储



    1. 在parse方法中设置返回值


    2. 执行终端指令:scrapy crawl spiderName -o ./duanzi.csv


    注意事项:



    1. 不能存入到数据库,只能对parse的返回值进行存储,且只能存入到指定后缀的文件中

    代码示例:/在工程名文件夹下的spiders文件夹中创建要爬虫的文件

    # -*- coding: utf-8 -*-
    import scrapy
    class FirstSpider(scrapy.Spider):
    # 爬虫名称:当前爬虫文件的唯一标识
    name = 'first'
    # 允许的域名
    # allowed_domains = ['www.baidu.com']
    # 起始的url列表:列表元素只可以是url
    # 作用:列表元素表示的url就会被进行请求发送
    start_urls = ['http://duanziwang.com/category/%E7%BB%8F%E5%85%B8%E6%AE%B5%E5%AD%90/']
    # 数据解析
    # 调用次数是由请求次数决定
    # def parse(self, response):
    # article_list = response.xpath('/html/body/section/div/div/main/article')
    # for article in article_list:
    # # xpath在进行数据提取时,返回的不再是字符串而是一个Selector对象,想要的数据被包含在了该对象的data参数中
    # # title = article.xpath('./div[1]/h1/a/text()')[0].extract()
    # title = article.xpath('./div[1]/h1/a/text()').extract_first()
    # cOntent= article.xpath('./div[2]//text()').extract()
    # cOntent= ''.join(content)
    # print(title,content)
    # 基于终端指令的持久化存储
    def parse(self, response):
    all_data = []
    article_list = response.xpath('/html/body/section/div/div/main/article')
    for article in article_list:
    # xpath在进行数据提取时,返回的不再是字符串而是一个Selector对象,想要的数据被包含在了该对象的data参数中
    # title = article.xpath('./div[1]/h1/a/text()')[0].extract()
    title = article.xpath('./div[1]/h1/a/text()').extract_first()
    cOntent= article.xpath('./div[2]//text()').extract()
    cOntent= ''.join(content)
    dic = {
    'title':title,
    'content':content
    }
    all_data.append(dic)
    return all_data # 将解析到的数据进行了返回


  • 基于管道的持久化存储



    1. 在爬虫文件中数据解析

    2. 将解析到的数据封装到一个叫做Item类型的对象

    3. 将item类型的对象提交给管道

    4. 管道负责调用process_item的方法接收item,然后进行某种形式的持久化存储

    5. 在配置文件中开启管道

    注意事项:



    1. 一个管道类对应一种形式的持久化存储,当需要存到不同的数据库或文件中,需要用到多个管道类


    2. process_item中的return item:可以将item提交给下一个即将被执行的管道类


    3. 如果直接将一个字典写入到redis报错的话/新版本不支持:pip install redis==2.10.6


    代码示例:

    settings配置文件

    ITEM_PIPELINES = {
    'duanzi.pipelines.DuanziPipeline': 300,
    }

    定义一个Item类:items.py

    import scrapy
    class DuanziproItem(scrapy.Item):
    title = scrapy.Field()
    cOntent= scrapy.Field()

    爬虫文件:duanzi.py

    class DuanziSpider(scrapy.Spider):
    name = 'duanzi'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://duanziwang.com/category/%E7%BB%8F%E5%85%B8%E6%AE%B5%E5%AD%90/']
    def parse(self, response):
    article_list = response.xpath('/html/body/section/div/div/main/article')
    for article in article_list:
    title = article.xpath('./div[1]/h1/a/text()').extract_first()
    cOntent= article.xpath('./div[2]//text()').extract()
    cOntent= ''.join(content)
    # 实例化一个item类型的对象,然后将解析到的一组数据存进去
    item = DuanziproItem()
    item['title'] = title
    item['content'] = content
    yield item # 将item提交给管道

    管道处理持久化存储:piplines.py

    import scrapy
    from DuanziPro.items import DuanziproItem
    class DuanziproPipeline(object):
    fp = None
    def open_spider(self,spider):
    print('开始爬虫......')
    self.fp = open('./duanzi.txt','w',encoding='utf-8')
    # 方法每被调用一次,参数item就是其接收到的一个item类型的对象
    def process_item(self, item, spider):
    # print(item) # item就是一个字典
    self.fp.write(item['title']+':'+item['content']+'\n')
    return item # 可以将item提交给下一个即将被执行的管道类
    def close_spider(self,spider):
    self.fp.close()
    print('爬虫结束!!!')

    多个管道类分别进行不同形式的存储

    # 将数据写入到文本文件中
    import pymysql
    from redis import Redis
    class DuanziproPipeline(object):
    fp = None
    def open_spider(self,spider):
    print('开始爬虫......')
    self.fp = open('./duanzi.txt','w',encoding='utf-8')
    # 方法每被调用一次,参数item就是其接收到的一个item类型的对象
    def process_item(self, item, spider):
    # print(item) # item就是一个字典
    self.fp.write(item['title']+':'+item['content']+'\n')
    return item # 可以将item提交给下一个即将被执行的管道类
    def close_spider(self,spider):
    self.fp.close()
    print('爬虫结束!!!')
    # 将数据写入到mysql
    class MysqlPipeLine(object):
    cOnn= None
    cursor = None
    def open_spider(self,spider):
    self.cOnn= pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='222',db='spider',charset='utf8')
    print(self.conn)
    def process_item(self,item,spider):
    sql = 'insert into duanzi values ("%s","%s")'%(item['title'],item['content'])
    self.cursor = self.conn.cursor()
    try:
    self.cursor.execute(sql)
    self.conn.commit()
    except Exception as e:
    print(e)
    self.conn.rollback()
    return item
    def close_spider(self,spider):
    self.cursor.close()
    self.conn.close()
    # 将数据写入到redis
    class RedisPileLine(object):
    cOnn= None
    def open_spider(self,spider):
    self.cOnn= Redis(host='127.0.0.1',port=6379)
    print(self.conn)
    def process_item(self,item,spider):
    self.conn.lpush('duanziData',item)
    return item



3. 全栈数据的爬取



  • 手动请求的发送

    yield scrapy.Request(url=new_url,callback=self.parse)
    # url:指定要发送请求的url
    # callback:指定对请求结果做解析的回调函数

    代码示例:

    # 全栈数据爬取对应的操作
    class DuanziSpider(scrapy.Spider):
    name = 'duanzi'
    start_urls = ['http://duanziwang.com/category/经典段子/']
    # 通用的url模板
    url = 'http://duanziwang.com/category/经典段子/%d/'
    pageNum = 1
    def parse(self, response):
    all_data = []
    article_list = response.xpath('/html/body/section/div/div/main/article')
    for article in article_list:
    title = article.xpath('./div[1]/h1/a/text()').extract_first()
    cOntent= article.xpath('./div[2]//text()').extract()
    cOntent= ''.join(content)
    # 实例化一个item类型的对象,然后将解析到的一组数据存进去
    item = DuanziproItem()
    item['title'] = title
    item['content'] = content
    yield item # 将item提交给管道
    # 编写手动请求的操作
    if self.pageNum <5:
    self.pageNum += 1
    print('正在下载的页码是:',self.pageNum)
    new_url = format(self.url%self.pageNum)
    yield scrapy.Request(url=new_url,callback=self.parse)

    总结:/什么时候用yield



    1. 向管道提交item的时候


    2. 手动请求发送的时候



  • 发送post请求

    yield scrapy.FromRequest(url=new_url,callback=self.parse,formdata={})
    # formdata:放post请求的参数


  • 为什么start_urls列表可以进行get请求的发送

    # 父类对start_requests的原始实现:
    class DuanziSpider(scrapy.Spider):
    name = 'duanzi'
    start_urls = ['http://duanziwang.com/category/经典段子/']
    # 通用的url模板
    url = 'http://duanziwang.com/category/经典段子/%d/'
    pageNum = 1
    def start_requests(self):
    for url in self.start_urls:
    yield scrapy.Request(url,callback=self.parse)



4. 五大核心组件/对象



  • 五大核心组件的作用:



    1. 引擎(ENGINE):

      用来处理整个系统的数据流处理, 触发事务(框架核心)


    2. 调度器(Scheduler):

      用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址


    3. 下载器(Downloader):

      用于下载网页内容, 并将网页内容返回给Spiders(Scrapy下载器是建立在twisted这个高效的异步模型上的)


    4. 爬虫(Spiders):

      爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面


    5. 项目管道(Pipeline):

      负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。




5. 适当提升scrapy爬取数据的效率



  • 增加并发:

    默认scrapy开启的并发线程为16个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。


  • 降低日志级别:

    在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘ERROR’


  • 禁止COOKIE:

    如果不是真的需要COOKIE,则在scrapy爬取数据时可以禁止COOKIE从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False


  • 禁止重试:

    对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False


  • 减少下载超时:

    如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s



6. 请求传参



  • 作用:帮助scrapy实现深度爬取

    深度爬取:爬取的数据没有在同一张页面中(例如:爬取图片时,首先是爬到图片的链接,再通过链接将图片爬取下来)


  • 需求:爬取名称和简介,https://www.4567tv.tv/frim/index1.html


  • 实现流程:

    传参:

    yield scrapy.Request(url,callback,meta), # 将meta这个字典传递给callback

    接收参数:

    response.meta


  • 代码示例:

    items.py

    import scrapy
    class MovieproItem(scrapy.Item):
    title = scrapy.Field()
    desc = scrapy.Field()

    爬虫文件/深度爬取:movie.py

    class MovieSpider(scrapy.Spider):
    name = 'movie'
    start_urls = ['https://www.4567tv.tv/index.php/vod/show/class/动作/id/1.html']
    url = 'https://www.4567tv.tv/index.php/vod/show/class/动作/id/1/page/%d.html'
    def parse(self, response):
    li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
    for li in li_list:
    title = li.xpath('.//div[@class="stui-vodlist__detail"]/h4/a/text()').extract_first()
    detail_url = 'https://www.4567tv.tv'+li.xpath('.//div[@class="stui-vodlist__detail"]/h4/a/@href').extract_first()
    item = MovieproItem()
    item['title'] = title
    # print(title,detail_url)
    # 对详情页的url进行手动请求发送
    # 请求传参:
    # 参数meta是一个字典,字典会传递给callback
    yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})
    # 自定义的另一个解析方法(必须要有response参数)
    def parse_detail(self,response):
    # 接收传递过来的meta
    item = response.meta['item']
    desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
    item['desc'] = desc
    yield item

    爬虫文件/全栈爬取+深度爬取:movie.py

    # 深度爬取+全栈爬取
    class MovieSpider(scrapy.Spider):
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567tv.tv/index.php/vod/show/class/动作/id/1.html']
    url = 'https://www.4567tv.tv/index.php/vod/show/class/动作/id/1/page/%d.html'
    pageNum = 1
    def parse(self, response):
    li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
    for li in li_list:
    title = li.xpath('.//div[@class="stui-vodlist__detail"]/h4/a/text()').extract_first()
    detail_url = 'https://www.4567tv.tv'+li.xpath('.//div[@class="stui-vodlist__detail"]/h4/a/@href').extract_first()
    item = MovieproItem()
    item['title'] = title
    # print(title,detail_url)
    # 对详情页的url进行手动请求发送
    # 请求传参:
    #参数meta是一个字典,字典会传递给callback
    yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})
    # 全栈爬取
    if self.pageNum <4:
    self.pageNum += 1
    new_url = format(self.url%self.pageNum)
    yield scrapy.Request(new_url,callback=self.parse)
    # 自定义的另一个解析方法(必须要有response参数)
    def parse_detail(self,response):
    # 接收传递过来的meta
    item = response.meta['item']
    desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
    item['desc'] = desc
    yield item

    pipelines.py

    class MovieproPipeline(object):
    def process_item(self, item, spider):
    print(item)
    return item




推荐阅读
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 本文深入探讨了 hCalendar 微格式在事件与时间、地点相关活动标记中的应用。作为微格式系列文章的第四篇,前文已分别介绍了 rel 属性用于定义链接关系、XFN 微格式增强链接的人际关系描述以及 hCard 微格式对个人和组织信息的描述。本次将重点解析 hCalendar 如何通过结构化数据标记,提高事件信息的可读性和互操作性。 ... [详细]
  • 2016-2017学年《网络安全实战》第三次作业
    2016-2017学年《网络安全实战》第三次作业总结了教材中关于网络信息收集技术的内容。本章主要探讨了网络踩点、网络扫描和网络查点三个关键步骤。其中,网络踩点旨在通过公开渠道收集目标信息,为后续的安全测试奠定基础,而不涉及实际的入侵行为。 ... [详细]
  • 在 Windows 10 系统下配置 Python 3 和 OpenCV 3 的环境时,建议使用 Anaconda 分发版以简化安装过程。Anaconda 可以从其官方网站(https://www.anaconda.com/download)下载。此外,本文还推荐了几本关于 Python 和 OpenCV 的专业书籍,帮助读者深入理解和应用相关技术。 ... [详细]
  • 在VMware虚拟机中部署带有中文图形界面的CentOS 7 Linux系统
    本文详细介绍了在VMware虚拟机中部署带有中文图形界面的CentOS 7 Linux系统的步骤。首先,通过“文件”菜单选择“新建虚拟机”并进入自定义设置。接着,在硬盘兼容性选项中选择默认设置。为了更好地进行Linux操作系统的安装练习,建议选择稍后安装操作系统,并在虚拟机安装完成后,根据实际需求删除不必要的硬件组件。此外,本文还提供了详细的配置参数和注意事项,帮助用户顺利完成整个部署过程。 ... [详细]
  • 本文探讨了Android系统中支持的图像格式及其在不同版本中的兼容性问题,重点涵盖了存储、HTTP传输、相机功能以及SparseArray的应用。文章详细分析了从Android 10 (API 29) 到Android 11 的存储规范变化,并讨论了这些变化对图像处理的影响。此外,还介绍了如何通过系统升级和代码优化来解决版本兼容性问题,以确保应用程序在不同Android版本中稳定运行。 ... [详细]
  • 利用树莓派畅享落网电台音乐体验
    最近重新拾起了闲置已久的树莓派,这台小巧的开发板已经沉寂了半年多。上个月闲暇时间较多,我决定将其重新启用。恰逢落网电台进行了改版,回忆起之前在树莓派论坛上看到有人用它来播放豆瓣音乐,便萌生了同样的想法。通过一番调试,终于实现了在树莓派上流畅播放落网电台音乐的功能,带来了全新的音乐享受体验。 ... [详细]
  • 本文详细探讨了Zebra路由软件中的线程机制及其实际应用。通过对Zebra线程模型的深入分析,揭示了其在高效处理网络路由任务中的关键作用。文章还介绍了线程同步与通信机制,以及如何通过优化线程管理提升系统性能。此外,结合具体应用场景,展示了Zebra线程机制在复杂网络环境下的优势和灵活性。 ... [详细]
  • 【Linux进阶指南】第一阶段第三课:体验与部署Ubuntu系统
    在正式踏上Linux学习之旅之前,本课程将引导你深入体验和部署Ubuntu系统。通过详细的操作步骤和实践演练,你将掌握Ubuntu的基本安装、配置及常用命令,为后续的进阶学习打下坚实的基础。此外,课程还将介绍如何解决常见问题和优化系统性能,帮助你更加高效地使用Ubuntu。 ... [详细]
  • TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得
    TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得 ... [详细]
  • 字节跳动深圳研发中心安全业务团队正在火热招募人才! ... [详细]
  • STAR: 转录组数据分析中的高效比对工具介绍
    欢迎关注“生信修炼手册”!STAR 是一款专为 RNA-seq 数据设计的高效比对工具,以其卓越的速度和高灵敏度著称。该软件在处理大规模转录组数据时表现出色,能够显著提高比对效率和准确性。此外,GATK 推荐使用 STAR 进行预处理步骤,以确保后续分析的可靠性。 ... [详细]
  • Python与R语言在功能和应用场景上各有优势。尽管R语言在统计分析和数据可视化方面具有更强的专业性,但Python作为一种通用编程语言,适用于更广泛的领域,包括Web开发、自动化脚本和机器学习等。对于初学者而言,Python的学习曲线更为平缓,上手更加容易。此外,Python拥有庞大的社区支持和丰富的第三方库,使其在实际应用中更具灵活性和扩展性。 ... [详细]
  • 本文深入探讨了IO复用技术的原理与实现,重点分析了其在解决C10K问题中的关键作用。IO复用技术允许单个进程同时管理多个IO对象,如文件、套接字和管道等,通过系统调用如`select`、`poll`和`epoll`,高效地处理大量并发连接。文章详细介绍了这些技术的工作机制,并结合实际案例,展示了它们在高并发场景下的应用效果。 ... [详细]
  • Python 数据分析领域不仅拥有高质量的开发环境,还提供了众多功能强大的第三方库。本文将介绍六个关键步骤,帮助读者掌握 Python 数据分析的核心技能,并深入探讨六款虽不广为人知但却极具潜力的数据处理库,如 Pandas 的替代品和新兴的可视化工具,助力数据科学家和分析师提升工作效率。 ... [详细]
author-avatar
小菜一蝶2502902341
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有