行业知识
Scrapy框架(高效爬虫)
文章目录
- 一、环境配置
- 二、创建项目
- 三、scrapy数据解析
- 四、基于终端指令的持久化存储
- 1、基于终端指令
- 2、基于管道
- 3、数据同时保存至本地及数据库
- 4、基于spider爬取某网站各页面数据
- 5、爬取本页和详情页信息(请求传参)
- 6、图片数据爬取ImagesPipeline
- 五、中间件
- 1、拦截请求中间件(UA伪装,代理IP)
- 2、拦截响应中间件(动态加载)
- 六、CrawlSpider(自动请求全站爬取,全部页面,自动下拉滚轮爬取)
- 七、分布式爬虫
- 八、增���式爬虫
Scrapy拥有高性能持久化存储,异步数据下载,高性能数据解析,分布式功能
一、环境配置
环境配置步骤如下(要按步骤来):
pip install wheel下载twisted:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted安装twisted:pip install Twisted-17.1.0-cp36m-win_amd64.whl (这个文件的路劲)pip install pywin32pip install scrapy测试:在终端输入scrapy指令,没有报错表示安装成功
二、创建项目
步骤:
1、打开pycharm的terminal2、scrapy startproject first3、cd first4、scrapy genspider main www.xxx.com5、需要有main.py里面的输出,则修改settings.py里面的ROBOTSTXT_OBEY = True改为False6、scrapy crawl main 不需要额外的输出则执行scrapy crawl main --nolog 或者在settings.py里面添加LOG_LEVEL='ERROR',main.py有错误代码会报错(不添加有错误时则不会报错)(常用)
实际操作如下:
打开pycharm的terminal
执行scrapy startproject first,当前目录下会出现个first项目工程,里面有个spiders文件夹,称为爬虫文件夹,在这里放爬虫源文件
cd first 进入工程目录
执行scrapy genspider main www.xxx.com,在spiders目录中创建一个名为main的爬虫文件,创建的文件自带部分内容
执行工程:scrapy crawl main (运行main爬虫文件)
上面parse里面如果有输出运行时没有输出,则需要将settings.py里面的ROBOTSTXT_OBEY = True改为False
改成False后,修改main.py文件内容如下,运行就会有输出
import scrapyclass MainSpider(scrapy.Spider): # 爬虫文件的名称:爬虫源文件的唯一标识 name = "main" # 允许的域名:用来限定start_urls列表中哪些url可以进行请求发送,一般不用 # allowed_domains = ["www.xxx.com"] # 起始的url列表:该列表中存放的url会被scrapy自动进行请求发送 start_urls = ["http://www.baidu.com/","https://www.sogou.com"] # 用于数据解析:response参数表示的就是请求成功后的响应对象 def parse(self, response): print(response) pass
使用指令scrapy crawl main --nolog,输出内容就不会输出多余的内容,只输出打印的内容
如果里面的代码输入错误,运行加上–nolog后不会有输出,看不出报错
有个好方法,运行不用加–nolog,在settings.py里面添加LOG_LEVEL='ERROR',如果输入错误,就会报ERROR,如果没错,输出内容和上面运行带上–nolog一样,这里就不用加–nolog
三、scrapy数据解析
首先创建项目
scrapy startproject firstcd firstscrapy genspider main www.xxx.com
修改settings.py文件的ROBOTSTXT_OBEY = True改为False,才会有输出,添加LOG_LEVEL='ERROR'
在将注释的USER_AGENT取消注释,在页面中复制该内容到这个变量中
修改main.py文件
import scrapyclass MainSpider(scrapy.Spider): name = "main" # allowed_domains = ["www.xxx.com"] start_urls = ["http://www.baidu.com/"] def parse(self, response): # 解析数据 # xpath返回的是列表,列表元素一定是Selector类型的对象 p_list = response.xpath('//p') for p in p_list: # extract可以将selector对象中data参数存储的字符串提取出来(可以是列表) print(p.extract())执行scrapy crawl main 就会将解析的数据输出
关于Xpath使用请看:https://blog.csdn.net/weixin_46287157/article/details/116432393
四、基于终端指令的持久化存储
1、基于终端指令
只可以将parse方法的返回值存储到本地的文本文件中
基于上面解析的数据,将要保存的数据保存在datas中,然后return返回
再执行指令scrapy crawl main -o ./a.csv,就可以将返回的datas数据保存在a.csv中(要加-o参数保存文件,也可以./a,txt)
注意:持久化存储的文本类型只可以为json, jsonlines, jsonl, jl, csv, xml, marshal, pickle
import scrapyclass MainSpider(scrapy.Spider): name = "main" allowed_domains = ["www.baidu.com"] start_urls = ["http://www.baidu.com/"] def parse(self, response): datas = [] # 解析数据 # xpath返回的是列表,列表元素一定是Selector类型的对象 p_list = response.xpath('//p[@]/p') for p in p_list: # extract可以将selector对象中data参数存储的字符串提取出来(可以是列表) datas.append(p.xpath('./p').extract()) return datas2、基于管道
首先需要创建项目:
1、打开pycharm的terminal2、scrapy startproject first3、cd first4、scrapy genspider main www.xxx.com5、修改settings.py里面的ROBOTSTXT_OBEY = True改为False并添加LOG_LEVEL='ERROR'6、scrapy crawl main
接着需要在主函数(main.py文件)中进行数据解析,main.py内容如下
import scrapyfrom first.items import FirstItemclass MainSpider(scrapy.Spider): name = "main" # allowed_domains = ["www.xxx.com"] start_urls = ["https://www.gushiwen.cn/"] def parse(self, response): # 解析数据 # xpath返回的是列表,列表元素一定是Selector类型的对象 p_list = response.xpath('/html/body/p[2]/p[1]/p') for p in p_list: # extract可以将selector对象中data参数存储的字符串提取出来(可以是列表) # 解析诗歌标题和内容 # 加个if判断,如果解析到的不为空,就进行存储 if len(p.xpath('./p[1]/p[1]/a/b/text()')) != 0 and len(p.xpath('./p[1]/p[2]/text()')) !=0: # 解析数据 title = p.xpath('./p[1]/p[1]/a/b/text()')[0].extract() content = p.xpath('./p[1]/p[2]/text()')[0].extract()然后在item类中定义相关的属性,将解析的数据存储到item类型的对象(items.py里面有个FirstItem类,可以实例化对象,即item类的实例对象)。修改items.py文件,定义相关属性,比如诗歌、内容,将解析到的数据封装到item对象中:
class FirstItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() content = scrapy.Field() pass
用item实例化对象后,这个对象就能取得title和content。将item类型的对象提交给管道进行持久化存储操作。pipelines.py中定义了FirstPipeline类,专门用来处理item类型对象。在管道类的process_item中要将其接受到的item对象中存储的数据进行持久化存储操作
# Define your item pipelines here## Don't forget to add your pipeline to the ITEM_PIPELINES setting# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html# useful for handling different item types with a single interfacefrom itemadapter import ItemAdapterclass FirstPipeline: fp = None # 重写父类的一个方法:该方法只在开始爬虫的时候被调用一次 def open_spider(self, spider): print('开启爬虫') self.fp = open('./a.txt', 'w', encoding='utf-8') # 用来处理item类型对象 # 该方法可以接收爬虫文件提交过来的item对象 # 该方法每接收到一个人item就会被调用一次 # 如果把打开关闭文件放这,则需要多次打开关闭文件,则另外创建函数,减少打开关闭文件次数 def process_item(self, item, spider): # item为item对象 title = item['title'] content = item['content'] self.fp.write(title+':'+content+'\n') return item def close_spider(self, spider): print('结束爬虫') self.fp.close()在配置文件setting.py中开启管道,即取消管道的注释
# Configure item pipelines# See https://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES = { "first.pipelines.FirstPipeline": 300,}最后在主函数main.py中添加调库及将解析的数据存储到item类型的对象和将item提交给管道的代码
import scrapyfrom first.items import FirstItemclass MainSpider(scrapy.Spider): name = "main" # allowed_domains = ["www.xxx.com"] start_urls = ["https://www.gushiwen.cn/"] def parse(self, response): # 解析数据 # xpath返回的是列表,列表元素一定是Selector类型的对象 p_list = response.xpath('/html/body/p[2]/p[1]/p') for p in p_list: # extract可以将selector对象中data参数存储的字符串提取出来(可以是列表) # 解析诗歌标题和内容 # 加个if判断,如果解析到的不为空,就进行存储 if len(p.xpath('./p[1]/p[1]/a/b/text()')) != 0 and len(p.xpath('./p[1]/p[2]/text()')) !=0: title = p.xpath('./p[1]/p[1]/a/b/text()')[0].extract() content = p.xpath('./p[1]/p[2]/text()')[0].extract() # 将解析的数据存储到item类型的对象 item = FirstItem() item['title'] = title item['content'] = content # 将item提交给管道,进行数据存储 yield item最后运行程序:scrapy crawl main
3、数据同时保存至本地及数据库
举例:将爬取的数据一份存到本地,一份存到数据库
在上面代码的基础上,再在管道中定义多个管道类,一个类制定存储到某个地方(一个存储到本地,一个存储到数据库)
在piplines.py中新增如下类
# 导入数据库# import pymysql# 管道文件中一个管道类对应将一组数据存储到一个平台或者载体中class mysqlPileLine(object): conn = None cursor = None def open_spider(self, spider): self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='123456', db='qiubai', charset='utf8') def process_item(self, item, spider): self.cursor =self.conn.cursor() try: self.cursor.execute('insert into qiubai values("%s","%s")'%(item["title"],item["content"])) self.conn.commit() except Exception as e: pritn(e) self.conn.rollback() return item def close_spider(self, spider): self.cursor.close() self.conn.close()在settings.py中开启管道,添加个优先级
# Configure item pipelines# See https://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES = { # 300表示优先级,数值越小,优先级越高 "first.pipelines.FirstPipeline": 300, "first.pipelines.mysqlPileLine": 301,}爬虫文件提交的item类型的对象最终会提交给先执行的类(优先级高的类)。在优先级高的里面添加return item,return就会传递给下一个即将执行的管道类,pipelines.py优先级高的类中给一个函数添加return
def process_item(self, item, spider): # item为item对象 title = item['title'] content = item['content'] self.fp.write(title+':'+content+'\n') # return就会传递给下一个即将执行的管道类 return item
管道文件中一个管道类对应的是将数据存储到一个平台。爬虫文件提交的item只会给管道文件中第一个被执行的管道类接收(优先级高的)。process_item中的return item表示将item传递给下一个即将被执行的管道类
4、基于spider爬取某网站各页面数据
以某网站为例,对某网站的全部页面(有分页栏)对应的页面进行爬取,这里需要获取所有页面的URL,并将其加入到start_url中,然后进行请求发送
首先创建项目并初始化操作
1、打开pycharm的terminal2、scrapy startproject first3、cd first4、scrapy genspider main www.xxx.com5、修改settings.py里面的ROBOTSTXT_OBEY = True改为False并添加LOG_LEVEL='ERROR'6、scrapy crawl main (最后一步运行)
然后编辑main.py文件
import scrapyclass MainSpider(scrapy.Spider): name = "main" # allowed_domains = ["www.xxx.com"] # 第一个页面 start_urls = ["https://www.woyaogexing.com/touxiang/katong/new/index.html"] # 生成一个通用的url # %d可以被page_num取代 url = 'https://www.woyaogexing.com/touxiang/katong/new/index_%d.html' # 页码数 page_num = 2 def parse(self, response): # 解析数据 p_list = response.xpath('/html/body/p[3]/p[3]/p[1]/p[2]/p') for li in p_list: img_name = li.xpath('./a[2]/text()')[0].extract() print(img_name) # 递归 if self.page_num 'item': item}) # 分页操作,爬取前5页数据 if self.page_num # 300表示优先级,数值越小,优先级越高 "first.pipelines.imgPipeline": 300,}# 在配置文件末尾添加文件存储目录IMAGES_STORE = './imgs' "middlePro.middlewares.MiddleproDownloaderMiddleware": 543,} "wangyiPro.middlewares.WangyiproDownloaderMiddleware": 543,}# Configure item pipelines# See https://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES = { "wangyiPro.pipelines.WangyiproPipeline": 300,}'item':item}) # 解析新闻内容 def parse_detail(self, response): content = response.xpath('').extract() content = ''.join(content) item = response.mate['item'] item['content'] = content yield item def close(self, spider): self.bro.quit()'scrapy_redis.pipelines.RedisPipeline':400}# 指定调度器# 增加一个去重容器类的配置,作用使用Redis的set集合来存储请求的指纹数据,从而实现请求取重的持久化存储DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"# 使用scrapy_redis组件自己的调度器SCHEDULER = "scrapy_redis.scheduler.Scheduler"# 配置调度器是否要持久化,也就是当爬虫结束了,要不要清空Redis中请求队列和去重指纹的set,如果TrueSCHEDULER_PERSIST = True# 指定redis服务器REDIS_HOST = 'redis服务器ip地址' # 写成redis远程服务器的ipREDIS_PORT = 6379 'name':item['name'] } self.conn.lpush('movieData', dic) return item
上一篇:自己的服务器怎么宣传?