昨天用Shell配合Python做了一个离线的作业控制系统,功能是有了,但是拓展性着实有点差,对小脚本小工具来说效果还可以,但是对于大型的爬虫类以及需要灵活控制的项目,可能就不太适合了。
毕设要做的课题已经确定是“网络爬虫程序”了,所以对爬虫的控制这一点是必不可少的,因此来总结一下今天学习的Scrapy以及Scrapyd。从开发,到部署一条龙的实现一下。
既然是一条龙,那么就把整体的流程走一下,详见下文。
环境
我的编码环境如下:
- OS: windows10
- Python:Python3.6
- Scrapy: Scrapy 1.5.0
- Scrapyd: twistd (the Twisted Windows runner) 17.9.0
具体的安装方式很简单,Python3.6自带了超好用的包管理工具pip,因此安装起来就很方便了。
pip install scrapy
# 如果已经安装了scrapy ,现在想升级的话也可以使用下面的命令
#pip install scrapy --upgrade
pip install scrapyd
pip install scrapyd-client
经过一段时间的等待,我们环境所依赖的应该就安装好了。
Scrapy爬虫框架
Scrapy有一个中文的Docs,讲的已经是很清晰了。需要参考细节的可以看看下面的链接 http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/overview.html
环境已经搭建好了,下面开始正式的编码。完成目标: 统计CSDN博客部分文章的信息(如标题,发表时间,浏览量,评论量等)。
创建项目
随便找一个目录,就可以开始了。具体的命令如下:
scrapy startproject csdn
# 意思是使用scrapy自带的templates下的basic模板创建一个project名为csdn的爬虫项目
创建完之后,我们会发现刚才的文件夹下多了一些文件,目录结构大致如下:
E:\CODE\PYTHON\ENVS\SCRAPYLEARN\CODES\CSDN
│ scrapy.cfg
│
└─csdn
│ csdn.article.json
│ items.py
│ middlewares.py
│ pipelines.py
│ settings.py
│ __init__.py
│
├─spiders
│ │ csdn_spider.py
│ │ __init__.py
scrapy.cfg文件以windows下的ini格式存储了我们的项目的配置信息,一般不怎么用改动,但是里面的信息很重要,这一点明确下还是比较好的。比如:
[settings]
default = csdn.settings
[deploy]
#url = http://localhost:6800/ # 部署爬虫项目的时候这个注释记得打开
project = csdn
剩下的文件,基本功能如下:
settings.py # 爬虫细节配置,基本上默认的就够了。但是有些可能也要手动改下,比如ROBOT协议是否要遵守(默认遵守,我们也可以手动打开来无视这个“君子协议”)
items.py # 定义爬取目标的数据结构,注意是结构哈。拓展部分见文档,
pipelines.py # 数据持久化的问题,具体是文件系统,数据库还是web存储服务商视具体情况而定
middlewares.py # 中间件服务,对这个例子来说,用不到
spider/ # 这个目录是我们要特别注意的,因为我们的爬虫代码的细节都要在这里面实现。
创建爬虫
因为今天我们要做的是关于CSDN文章的爬虫,所以这里为了见名之意,就起了个名为csdn_spider.py
,这一步可以手动创建,也可以借助scrapy的genspider自命令来实现。后者实际上是使用的scrapy的自带的爬虫模板自动生成的。
# 记得在爬虫的根目录(包含了scrapy.cfg文件的那层哈)
scrapy genspider csdn
具体的继承细节这类的直接看文档来的更清晰,这不再过多赘述,就直接贴代码了。
import scrapy
from csdn.items import CsdnItem
class CsdnSpider(scrapy.Spider):
name = "csdn"
allowed_domains = ["csdn.net"]
start_urls = ["http://blog.csdn.net/marksinoberg/"]
def parse(self, response):
# print(response.request)
# //*[@id="papelist"]/div/nav/ul/li
# urls = response.xpath('//*[@id="papelist"]/div/nav/ul/li')
pageurls = response.xpath('//*[@id="papelist"]/div/nav/ul/li/a/@href').extract()
for url in pageurls:
pageurl = "http:" + url
yield scrapy.Request(url=pageurl, callback=self.parse_out_article_url)
def parse_out_article_url(self, response):
# //*[@id="article_list"]/div[18]/div
articleurls = response.xpath('//*[@id="article_list"]/div/div/h1/span/a/@href').extract()
for url in articleurls:
articleurl = "http:" + url
yield scrapy.Request(articleurl, callback=self.parse_each_article)
def parse_each_article(self, response):
title = response.xpath("/html/head/title/text()").extract_first()
postdate = response.xpath('//*[@id="article_details"]/div[2]/div[2]/span[1]/text()').extract_first()
watches = response.xpath('//*[@id="article_details"]/div[2]/div[2]/span[2]/text()').extract_first()
comments = response.xpath('//*[@id="article_details"]/div[2]/div[2]/span[3]/text()').extract()[1]
# comments = response.xpath('//*[@id="article_details"]/div[2]/div[2]/span[3]/text()').extract[0]
item = CsdnItem()
item['title'] = title
item['url'] = response.url
item['postdate'] = postdate
item['watches'] = watches
item['comments'] = comments
print(title + " | " + postdate + " | " + watches + " | " + comments)
return item
具体的思路就是,通过start_urls指定的URL。抓到页面后提取出里面的博客页码对应的链接(每一页里面都会有很多篇具体的文章)。对每一个页进行抓取,然后再对每一篇博客进行具体的解析。
这里start_urls下只能看到5个页面(实际上是4个,CSDN的当前页没有链接,这一点没做处理,其实直接处理也是很方便的,受益于yield嘛,哈哈)。
思路很清晰,但是要理解request和response的工作流程还是有点绕的。这里也简单描述下。
scrapy 通过start_urls创建request对象,同时callback方法(默认是parse)会被作为一个参数传给Request构造方法,这样,底层完成Request后,将返回的response作为一个结果集传给callback方法,这样的异步处理,不仅方便而且不会阻塞,可谓是有很多好处。
至此,爬虫已经编写完毕了。
E:\Code\Python\envs\scrapylearn\codes\csdn\csdn>scrapy list
csdn
运行爬虫
现在代码也已经编写完毕了。直接运行爬虫就好。运行爬虫有很多种方式。我们可以通过指定py爬虫文件的方式,或者爬虫名称的方式来运行刚才编写完毕的爬虫。
# 需要进入到spider目录哈
scrapy runspider csdn_spider.py
scrapy crawl csdn # 会输出爬虫整个生命流程的所有输出,便于调试
scrapy crawl csdn --nolog # 只打印爬虫内部的输出信息,不会有调试信息输出,看起来更加简洁。
scrapy crawl --nolog csdn -o csdn.article.json # 将爬虫信息重定向输出到文件中
这里我就以第二个命令作为示例吧。
E:\Code\Python\envs\scrapylearn\codes\csdn\csdn>scrapy crawl --nolog csdn -o csdn.article.json
类Flask实现前后端交互之代码聊天室 - CSDN博客 | 2017年06月01日 09:18:25 | 8308人阅读 | (4)
冒泡排序核心教程 - CSDN博客 | 2015年09月26日 18:59:48 | 6886人阅读 | (0)
选择排序 - CSDN博客 | 2015年09月26日 19:15:03 | 6545人阅读 | (0)
Nodejs之静态资源处理 - CSDN博客 | 2017年06月04日 18:52:35 | 10003人阅读 | (0)
Nodejs 实用工具集笔记 - CSDN博客 | 2017年06月03日 21:33:16 | 6841人阅读 | (0)
Tkinter小结 界面+快捷键设置 - CSDN博客 | 2017年04月21日 17:41:03 | 7975人阅读 | (1)
CSDN 博客备份工具 - CSDN博客 | 2017年04月29日 10:59:48 | 9393人阅读 | (15)
Nginx 从零搭建 - CSDN博客 | 2017年05月04日 16:04:27 | 6086人阅读 | (0)
pymongo 存取 - CSDN博客 | 2017年04月22日 14:23:23 | 10709人阅读 | (3)
给自己看的Redis - CSDN博客 | 2017年05月09日 17:02:47 | 5828人阅读 | (1)
Java 程序员 面试前必备知识 - CSDN博客 | 2017年04月18日 10:40:24 | 12288人阅读 | (12)
语音聊天 - CSDN博客 | 2017年05月11日 16:17:14 | 8561人阅读 | (5)
我的MongoDB坎坷之路 - CSDN博客 | 2016年12月06日 17:31:20 | 11056人阅读 | (7)
处理音频--pyaudio - CSDN博客 | 2017年05月10日 20:05:15 | 10822人阅读 | (1)
QQ空间 代码秒赞 - CSDN博客 | 2016年12月13日 15:42:00 | 8680人阅读 | (4)
解决服务器上部署PHP程序异常 - CSDN博客 | 2016年12月13日 19:02:22 | 6749人阅读 | (0)
抓取网易云音乐歌曲热门评论生成词云 - CSDN博客 | 2017年04月26日 17:34:09 | 26285人阅读 | (25)
实时体重检测 - CSDN博客 | 2016年12月11日 15:19:43 | 7807人阅读 | (8)
PHP 数据库连接池实现 - CSDN博客 | 2016年12月24日 12:52:02 | 18269人阅读 | (7)
扫码登陆 之我见 - CSDN博客 | 2016年12月16日 13:53:12 | 10203人阅读 | (4)
PHP 反射技术 - CSDN博客 | 2016年12月24日 15:12:10 | 6821人阅读 | (0)
在线 PHP运行工具、数据库可控 - CSDN博客 | 2016年12月25日 14:41:58 | 8409人阅读 | (2)
数据库模块模块 小扳手 - CSDN博客 | 2017年01月21日 23:14:41 | 5756人阅读 | (1)
用微信 远程遥控 服务器 - CSDN博客 | 2017年01月08日 19:31:04 | 8596人阅读 | (5)
网站访客 简易日志记录 - CSDN博客 | 2016年12月30日 19:52:46 | 8931人阅读 | (4)
在线 Python运行工具 - CSDN博客 | 2016年12月26日 10:32:02 | 9654人阅读 | (2)
代理IP 有效性检测 - CSDN博客 | 2017年01月07日 12:17:52 | 22830人阅读 | (1)
PHP 伪静态 - CSDN博客 | 2017年01月28日 18:17:33 | 5484人阅读 | (0)
php 处理 非法访问 - CSDN博客 | 2017年01月29日 21:50:23 | 6286人阅读 | (0)
php拓展 包管理工具 - CSDN博客 | 2017年01月24日 14:33:21 | 6685人阅读 | (0)
后台站点文件扫描 - CSDN博客 | 2017年02月03日 21:08:05 | 6746人阅读 | (0)
PFSI 开源啦,欢迎您来贡献您的代码 - CSDN博客 | 2017年02月06日 15:51:58 | 7343人阅读 | (2)
Apache 常识小札 - CSDN博客 | 2017年01月30日 21:58:07 | 5930人阅读 | (2)
Markdown转HTML之Node篇 - CSDN博客 | 2017年06月06日 21:55:28 | 7984人阅读 | (0)
easyui Basic CRUD Application 试水 - CSDN博客 | 2017年02月02日 16:46:54 | 6311人阅读 | (1)
Nodejs-cli 填坑记 - CSDN博客 | 2017年06月12日 15:26:31 | 7579人阅读 | (3)
命令行进度条实现 - CSDN博客 | 2017年06月19日 20:40:21 | 7007人阅读 | (0)
打包发布自己的nodejs包 - CSDN博客 | 2017年06月13日 22:37:18 | 10486人阅读 | (2)
技能雷达图 - CSDN博客 | 2017年06月22日 14:04:49 | 7563人阅读 | (9)
ajax跨域问题解决方案 - CSDN博客 | 2017年06月20日 17:05:15 | 8014人阅读 | (1)
一个不成熟的模板引擎思路 - CSDN博客 | 2017年06月13日 16:38:45 | 6521人阅读 | (1)
Web访问控制 - CSDN博客 | 2017年07月13日 16:14:30 | 7380人阅读 | (9)
tmux安装与使用 - CSDN博客 | 2017年08月03日 14:53:54 | 6568人阅读 | (1)
在线考试实时拍照系统 - CSDN博客 | 2017年07月16日 23:00:59 | 8048人阅读 | (1)
MySQL笔记之多表 - CSDN博客 | 2017年07月05日 15:04:04 | 6062人阅读 | (0)
图片上传预览原理及实现 - CSDN博客 | 2017年07月10日 19:38:56 | 8972人阅读 | (3)
Python自定义大小截屏 - CSDN博客 | 2017年07月24日 22:43:12 | 8182人阅读 | (9)
图解VIM常用操作 - CSDN博客 | 2017年08月26日 14:01:12 | 7021人阅读 | (14)
在偷懒的路上越走越远 - CSDN博客 | 2017年08月19日 12:15:16 | 5485人阅读 | (4)
Nginx-一个IP配置多个站点 - CSDN博客 | 2017年09月03日 12:10:48 | 9190人阅读 | (3)
ctags,cscope,nerdtree,tmux 笔记 - CSDN博客 | 2017年09月16日 16:37:20 | 8111人阅读 | (5)
谈谈反爬虫“政策与对策” - CSDN博客 | 2017年10月07日 09:48:05 | 5473人阅读 | (10)
我与阿里云的故事 - CSDN博客 | 2017年02月07日 21:07:56 | 6762人阅读 | (10)
DWR3.0 服务器推送及解惑 - CSDN博客 | 2017年02月17日 10:42:59 | 7681人阅读 | (13)
我的worktools集合们 - CSDN博客 | 2017年08月27日 13:03:24 | 5443人阅读 | (0)
你这个requests啊 - CSDN博客 | 2017年09月21日 23:40:40 | 20902人阅读 | (2)
网页全截图实现 - CSDN博客 | 2017年02月28日 20:48:31 | 6766人阅读 | (2)
《提问的艺术》读后感 - CSDN博客 | 2017年02月25日 15:02:50 | 7055人阅读 | (1)
重新认识 Sublime Text 3 - CSDN博客 | 2017年02月24日 17:45:38 | 6661人阅读 | (0)
几个面试常考的问题 - CSDN博客 | 2017年03月05日 11:48:44 | 7180人阅读 | (1)
懒人翻译 - CSDN博客 | 2017年03月17日 17:11:44 | 6570人阅读 | (3)
SSH 搭建点滴 - CSDN博客 | 2017年03月15日 20:34:55 | 6577人阅读 | (5)
认真对待 Python3 收邮件 - CSDN博客 | 2017年03月27日 12:01:34 | 12563人阅读 | (13)
CI之旅 - CSDN博客 | 2017年03月30日 16:51:47 | 6024人阅读 | (0)
Python 模拟登录知乎 - CSDN博客 | 2017年04月07日 17:03:51 | 11109人阅读 | (47)
记 dotamax 面试第一题 - CSDN博客 | 2017年04月13日 19:17:00 | 6295人阅读 | (0)
Python 实现一个全面的单链表 - CSDN博客 | 2017年04月05日 19:28:50 | 8121人阅读 | (2)
Python 实现二叉树相关操作 - CSDN博客 | 2017年04月06日 20:58:12 | 6712人阅读 | (0)
半自动化生成README.md文件 - CSDN博客 | 2017年04月14日 20:32:20 | 6355人阅读 | (0)
2017 携程 笔试编程题 1 - CSDN博客 | 2017年04月11日 22:05:40 | 6828人阅读 | (2)
Java String 真的是不可变的吗 - CSDN博客 | 2017年03月08日 15:52:44 | 7111人阅读 | (0)
当模拟登陆遇到验证码 - CSDN博客 | 2017年04月09日 21:56:29 | 8348人阅读 | (2)
“社交网络”分析 - CSDN博客 | 2017年05月18日 15:27:12 | 7940人阅读 | (6)
关于站内搜索的那些事儿 - CSDN博客 | 2017年05月12日 13:10:37 | 8519人阅读 | (9)
读《卓越程序员密码》有感 - CSDN博客 | 2017年05月21日 13:51:34 | 5734人阅读 | (1)
知乎用户分布研究 - CSDN博客 | 2017年05月22日 15:36:45 | 7792人阅读 | (6)
爬取微博用户数据 - CSDN博客 | 2017年05月21日 20:34:06 | 6584人阅读 | (1)
Flask中的ORM使用 - CSDN博客 | 2017年05月24日 14:05:26 | 11903人阅读 | (1)
Django应用部署 - CSDN博客 | 2017年05月30日 11:43:30 | 6290人阅读 | (0)
装饰器实现路由控制 - CSDN博客 | 2017年05月30日 19:51:16 | 6125人阅读 | (0)
至此,整个爬虫已经全部调试通过。至于xpath和css这些Selector,我个人建议还是看官方文档来得实惠。而且讲的也更加的清晰。
Scrapyd爬虫部署服务
windows 下部署命令不识别的问题
下面进入第二个阶段,部署我们刚才已经完成的爬虫项目。安装好了scrapyd和scrapd-client后,我们可能会遇到scrapyd-deploy不是windows下的命令的问题。这是由于环境变量找不到导致的。
解决办法也很简单。在python的安装目录下创建俩同名的bat批处理文件即可。
开启scrapyd服务
这样就可以正常使用部署爬虫的命令了。在部署爬虫之前,先开启scrapyd的服务。具体的命令如下:
developer@aliyun~#scrapyd
2018-03-13T21:54:45+0800 [-] Loading d:\software\python3\lib\site-packages\scrapyd\txapp.py...
2018-03-13T21:54:46+0800 [-] Scrapyd web console available at http://127.0.0.1:6800/
2018-03-13T21:54:46+0800 [-] Loaded.
2018-03-13T21:54:46+0800 [twisted.application.app.AppLogger#info] twistd 17.9.0 (d:\software\python3\python.exe 3.6.0) starting up.
2018-03-13T21:54:46+0800 [twisted.application.app.AppLogger#info] reactor class: twisted.internet.selectreactor.SelectReactor.
2018-03-13T21:54:46+0800 [-] Site starting on 6800
2018-03-13T21:54:46+0800 [twisted.web.server.Site#info] Starting factory <twisted.web.server.Site object at 0x0000019D2BDFC320>
2018-03-13T21:54:46+0800 [Launcher] Scrapyd 1.2.0 started: max_proc=16, runner='scrapyd.runner'
部署爬虫
服务已经开启,这个时候要记得打开scrapy.cfg中的deploy的url参数。否则scrapy爬虫部署可能就失败了。
[deploy:csdndeploy]
url = http://localhost:6800/
project = tutorial
注意[deploy:csdndeploy] 的格式,意思是target为csdndeploy的部署配置。有其他的部署可以通过冒号后面的target名称进行单独设置。
然后具体的部署命令是:
E:\Code\Python\envs\scrapylearn\codes\csdn\csdn>scrapyd-deploy csdndeploy -p csdn
Packing version 1520952421
Deploying to project "csdn" in http://localhost:6800/addversion.json
Server response (200):
{"node_name": "DESKTOP-5U5QNB2", "status": "ok", "project": "csdn", "version": "1520952421", "spiders": 1}
按照输出信息的提示,我们只需要访问http://localhost:6800/addversion.json 资源就可以看到具体的部署信息了。
作业控制
scrapyd的官方文档也是很详细,我们可以通过对schedule.json,cancle.json等资源来实现以HTTP服务的方式控制爬虫。具体的文档为http://scrapyd.readthedocs.io/en/latest/api.html
比如下面的开启爬虫:
$ curl http://localhost:6800/schedule.json -d project=csdn -d spider=csdn
然后的下面的结果就说明已经成功开启了一个爬虫。
biao@DESKTOP-5U5QNB2 MINGW64 /e/Code/Python/envs/scrapylearn/codes/csdn
$ curl http://localhost:6800/schedule.json -d project=csdn -d spider=csdn
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 118 100 94 100 24 31 7 0:00:03 0:00:03 --:--:-- 31{"node_name": "DESKTOP-5U5QNB2", "status": "ok", "jobid": "4b39330c26ce11e8834a74d02bba7257"}
然后就可以看到具体的爬虫运行信息了。http://localhost:6800/jobs
我这里的结果如下:
点击“Log”超链接,就可以看到爬虫的具体的输出信息了。
其他HTTP操作类似,就不再过多的赘述了。参考官方文档即可。
总结
上一篇文章写了制作一个离线的作业控制系统,而今天这里用到的scrapyd就是一个底层使用了twisted的集成了的IPC服务套件(注意即使是同一个spider,两次run也要放到不同的JOBDIR,具体可以参考文档),很方便。然而自己去实现的话,对这块的内容也会理解的更深刻。