51Testing软件测试论坛
标题:
Pyspider快速上手
[打印本页]
作者:
测试积点老人
时间:
2018-12-3 16:23
标题:
Pyspider快速上手
本帖最后由 测试积点老人 于 2018-12-3 16:25 编辑
pyspider简介:
PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI。采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器,任务监视器,项目管理器以及结果查看器。
pyspider是作者之前做的一个爬虫架构的开源化实现。主要的功能需求是:
1.抓取、更新调度多站点的特定的页面
2.需要对页面进行结构化信息提取
3.灵活可扩展,稳定可监控
而这也是绝大多数python爬虫的需求 —— 定向抓取,结构化化解析。但是面对结构迥异的各种网站,单一的抓取模式并不一定能满足,灵活的抓取控制是必须的。为了达到这个目的,单纯的配置文件往往不够灵活,于是,通过脚本去控制抓取是我最后的选择。
而去重调度,队列,抓取,异常处理,监控等功能作为框架,提供给抓取脚本,并保证灵活性。最后加上web的编辑调试环境,以及web任务监控,即成为了这套框架。
pyspider的设计基础是:以python脚本驱动的抓取环模型爬虫
通过python脚本进行结构化信息的提取,follow链接调度抓取控制,实现最大的灵活性
开发快速上手:
通过web化的脚本编写、调试环境。web展现调度状态
抓取环模型成熟稳定,模块间相互独立,通过消息队列连接,从单进程到多机分布式灵活拓展
主要函数解释:
def on_start(self) 方法是入口代码。当在web控制台点击run按钮时会执行此方法。
self.crawl(url, callback=self.index_page)这个方法是调用API生成一个新的爬取任务,这个任务被添加到待抓取队列。
def index_page(self, response) 这个方法获取一个Response对象。 response.doc是pyquery对象的一个扩展方法。pyquery是一个类似于jQuery的对象选择器。
def detail_page(self, response)返回一个结果集对象。这个结果默认会被添加到resultdb数据库(如果启动时没有指定数据库默认调用sqlite数据库)。你也可以重写on_result(self,result)方法来指定保存位置。
更多知识:
@every(minutes=24*60, seconds=0) 这个设置是告诉scheduler(调度器)on_start方法每天执行一次。
@config(age=10 * 24 * 60 * 60) 这个设置告诉scheduler(调度器)这个request(请求)过期时间是10天,10天内再遇到这个请求直接忽略。这个参数也可以在self.crawl(url, age=10*24*60*60) 和 crawl_config中设置。
@config(priority=2) 这个是优先级设置。数字越小越先执行。
以爬取财经网财经热评为例:启动函数on_start:
@every(minutes=24 * 60)
def on_start(self):
self.crawl('http://comments.caijing.com.cn/hottopics/', callback=self.index_page)
复制代码
调用内置函数self.crawl,生成response对象,传给回调函数index_page
@config(age=10 * 24 * 60 * 60)
def index_page(self, response):
# 选择所有href属性以http开头的a标签
for each in response.doc('a[href^="http"]').items():
# 判断该标签是否是《新闻评论》详情的url
if re.match('http://comments.caijing.com.cn/\d+', each.attr.href, re.U):
# 再次发送请求,回调函数为最终的解析函数
self.crawl(each.attr.href, callback=self.detail_page)
复制代码
进入解析方法,解析页面。response.etree是内置方法,它生成一个html的etree对象
@config(priority=2)
def detail_page(self, response):
data = {
"url": response.url,
# 调用xpath提取title
"title": response.etree.xpath('//*[@id="cont_title"]/text()')[0]
}
return data
复制代码
全部代码:
import re
import json
class Handler(BaseHandler):
crawl_config = {
}
@every(minutes=24 * 60)
def on_start(self):
self.crawl('http://comments.caijing.com.cn/hottopics/', callback=self.index_page, force_update=True)
@config(age=10 * 24 * 60 * 60)
def index_page(self, response):
for each in response.doc('a[href^="http"]').items():
if re.match('http://comments.caijing.com.cn/\d+', each.attr.href, re.U):
self.crawl(each.attr.href, callback=self.detail_page)
elif re.match('http://comments.caijing.com.cn/hottopics/\d+.shtml', each.attr.href, re.U):
self.crawl(each.attr.href, callback=self.index_page, force_update=True)
@config(priority=2)
def detail_page(self, response):
etree = response.etree
print type(etree.xpath('//*[@id="cont_title"]/text()')[0].encode('utf-8'))
data = {
"url": response.url,
"title": etree.xpath('//*[@id="cont_title"]/text()')[0].encode('utf-8'),
"content":'\n'.join(etree.xpath('//*[@id="the_content"]/p/text()')).encode('utf-8'),
"post_time":etree.xpath('//*[@id="pubtime_baidu"]/text()')[0].encode('utf-8'),
"source":etree.xpath('//span[@id="source_baidu"]//text()')[0].encode('utf-8'),
}
return data
def on_result(self, result):
if not result:
return
sql = SQL()
sql.replace('article', result)
复制代码
欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/)
Powered by Discuz! X3.2