爬虫之scrapy框架(一)
目录
一、scrapy简介,架构介绍
1.1scrapy简介
Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分广泛,可用于如数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。整体架构大致如下
1.2架构介绍
The data flow in Scrapy is controlled by the execution engine, and goes like this:
- The Engine gets the initial Requests to crawl from the Spider.
- The Engine schedules the Requests in the Scheduler and asks for the next Requests to crawl.
- The Scheduler returns the next Requests to the Engine.
- The Engine sends the Requests to the Downloader, passing through the Downloader Middlewares (see
process_request()
). - Once the page finishes downloading the Downloader generates a Response (with that page) and sends it to the Engine, passing through the Downloader Middlewares (see
process_response()
). - The Engine receives the Response from the Downloader and sends it to the Spider for processing, passing through the Spider Middleware (see
process_spider_input()
). - The Spider processes the Response and returns scraped items and new Requests (to follow) to the Engine, passing through the Spider Middleware (see
process_spider_output()
). - The Engine sends processed items to Item Pipelines, then send processed Requests to the Scheduler and asks for possible next Requests to crawl.
- The process repeats (from step 1) until there are no more requests from the Scheduler.
Components:
引擎(EGINE)
引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。有关详细信息,请参见上面的数据流部分。
调度器(SCHEDULER)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址下载器(DOWLOADER)
用于下载网页内容, 并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的爬虫(SPIDERS)
SPIDERS是开发人员自定义的类,用来解析responses,并且提取items,或者发送新的请求项目管道(ITEM PIPLINES)
在items被提取后负责处理它们,主要包括清理、验证、持久化(比如存到数据库)等操作下载器中间件(Downloader Middlewares)
位于Scrapy引擎和下载器之间,主要用来处理从EGINE传到DOWLOADER的请求request,已经从DOWNLOADER传到EGINE的响应response,你可用该中间件做以下几件事
- process a request just before it is sent to the Downloader (i.e. right before Scrapy sends the request to the website);
- change received response before passing it to a spider;
- send a new Request instead of passing received response to a spider;
- pass response to a spider without fetching a web page;
- silently drop some requests.
爬虫中间件(Spider Middlewares)
位于EGINE和SPIDERS之间,主要工作是处理SPIDERS的输入(即responses)和输出(即requests)
1.3安装
windows/mac/linux:pip3 install scrapy #windows优先采用上面的方式进行安装,如果报错再采用下面的方式 windwos: -pip3 install scrapy(大部分同学直接是可以的) -如果上面不行 -pip3 install wheel (xxx.whl文件安装模块) -下载pywin32:两种方式:1 pip3 install pywin32 2 下一个exe安装https://sourceforge.net/projects/pywin32/files/pywin32/ -下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 下载完是一个xxx.whl文件 -执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
命令行工具
#1 查看帮助 scrapy -h scrapy <command> -h #2 有两种命令:其中Project-only必须切到项目文件夹下才能执行,而Global的命令则不需要 Global commands: startproject #创建项目 genspider #创建爬虫程序 settings #如果是在项目目录下,则得到的是该项目的配置 runspider #运行一个独立的python文件,不必创建项目 shell #scrapy shell url地址 在交互式调试,如选择器规则正确与否 fetch #独立于程单纯地爬取一个页面,可以拿到请求头 view #下载完毕后直接弹出浏览器,以此可以分辨出哪些数据是ajax请求 version #scrapy version 查看scrapy的版本,scrapy version -v查看scrapy依赖库的版本 Project-only commands: crawl #运行爬虫,必须创建项目才行,确保配置文件中ROBOTSTXT_OBEY = False check #检测项目中有无语法错误 list #列出项目中所包含的爬虫名 edit #编辑器,一般不用 parse #scrapy parse url地址 --callback 回调函数 #以此可以验证我们的回调函数是否正确 bench #scrapy bentch压力测试
二、scrapy创建项目及介绍
2.1项目创建
# 通过命令创建项目,到指定的文件夹下 # 创建项目(django中创建项目) scrapy startproject 项目名字 # 创建爬虫(django中创建app)在spiders文件夹下创建一个py文件,一个py文件就是一个爬虫(不要注册,没有注册一说) scrapy genspider 爬虫名字 爬取的地址 scrapy genspider chouti dig.chouti.com # 打开项目,pycharm打开 # 运行爬虫 命令行下 scrapy crawl 爬虫名字 scrapy crawl 爬虫名字 --nolog # 不打印日志 # 运行爬虫 py文件 在项目目录下创建一个py文件,假设叫main.py,点击右键执行即可执行爬虫,等同于命令 from scrapy.cmdline import execute execute(['scrapy','crawl','chouti'])
2.2目录介绍
-scarpyfirst 项目名 -scrapy.cfg 上线相关的 -scrapyfirst 文件夹 -spiders文件夹 :所有的爬虫写在这里面 -chouti.py :一个py文件就是一个爬虫(类似于django的app) -items.py :配合管道,做数据存储(类似于django中models.py 写一个个的模型类) -middlewares.py :中间件(爬虫中间件,下载中间件都写在这里面) -pipelines.py :管道,持久化相关,数据存储卸载这 -settings.py :配置文件相关
2.3settings介绍
一般爬虫项目需要进行下面的配置,关于settings的详细介绍见下一篇scrapy文章。
#配置文件全是大写 ROBOTSTXT_OBEY = True #是否遵循爬虫协议,如果是true,基本上网站都爬不了,遵循要爬取网站的爬虫协议,一般设置成false USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36' LOG_LEVEL='ERROR' # 只打印错误信息
三、scrapy的数据解析(重点)
关于详细的css、xpath选择器介绍请看上一篇文章,这里只介绍属性和文本的选择
3.1css选择器
css选择 response.css('标签').extract() #取所有标签 response.css('标签').extract_first()#获取一个标签 用的比较多 response.css('标签::attr(属性)').extract_first() #选取标签的属性 response.css('标签::text').extract_first()#选取标签内的文本 response.css('a::attr(href)').extract_first() response.css('p::text').extract_first()
3.2xpath选择
response.xpath('').extract_first() #获取一个标签 用的比较多 response.xpath('./div/div/div[1]/a/text()').extract_first()#获取标签内文本 response.xpath('./@属性').extract_first()#获取标签内属性
四、scrapy的持久化存储(重点)
持久化存储有两种方式:
第一种:通过命令:scrapy crawl chout -o aa.csv (用的比较少)需要在parser解析方法中返回列表套字典的格式。
第二种:通过管道方式,大部分使用这种方式
4.1持久化到文件
在pipelines.py中,open_spider打开文件,process_item里写入文件,close_spider关闭文件。执行的步骤是先执行open_spider,然后执行process_item将爬取到的所有数据写入,所有的爬虫结束执行close_spider。
class ChoutiPipeline(object): def open_spider(self,spider): print('我开了') self.f=open('a.txt','w') def process_item(self, item, spider): self.f.write(item['desc'] + item['img_url']) self.f.write('\n') return item def close_spider(self,spider): self.f.close() print("我关了")
4.2持久化到数据库
在4.1版本上稍作改变将文本写入改为写入数据库就行了,代码如下:
import pymysql # 存文件 class ChoutiMysqlPipeline(object): def open_spider(self, spider): # autocommit=True 表示自动提交 self.conn=pymysql.connect(host='127.0.0.1', user='root', password="123",database='chouti', port=3306) def process_item(self, item, spider): cursor=self.conn.cursor() sql="insert into article (`desc`,img_url) values ('%s','%s')"%(item['desc'],item['img_url']) cursor.execute(sql) self.conn.commit()#不要忘了提交 def close_spider(self, spider): self.conn.close()
settings.py中进行如下配置
ITEM_PIPELINES = { 'scrapyfirst.pipelines.ChoutiPipeline': 300, 'scrapyfirst.pipelines.ChoutiMysqlPipeline': 302, }