pyspider框架介绍
pyspider 是个强大的由python实现的爬虫系统。
如果使用ubuntu
,请先运行sudo apt update
再运行sudo apt upgrade
更新
apt-get install python python-dev python-distribute python-pip \
libcurl4-openssl-dev libxml2-dev libxslt1-dev python-lxml \
libssl-dev zlib1g-dev
删除wsgidav
然后重新安装2.4.1
版本
https://www.lfd.uci.edu/~gohlke/pythonlibs/ 中下载pycurl
安装
windows 下安装成功,运行报如下错误:
Deprecated option 'domaincontroller': use 'http_authenticator.domain_controller' instead.
解决方案:
删除wsgidav
然后重新安装2.4.1
版本
安装好pyspider
后,创建一个项目文件夹用来存放相关文件,进入文件夹后运行pyspider
命令,默认情况下会运行一个web服务端监听5000端口,通过http://localhost:5000
即可访问pyspider的web管理界面,它看起来是这样的:
项目是独立的,但您可以将另一个项目作为模块导入 from projects import other_project 一期工程有5个状态:TODO,STOP,CHECKING,DEBUG和RUNNING
因为我身处东莞,所以爬取的是东莞的
https://dg.lianjia.com/ershoufang/
进入到了开发界面
def on_start(selef)
是脚本的入口。当你点击run
按钮时,它会被调用。self.crawl(url, callback=self.index_page)
是最重要的接口。它会添加一个新的待爬取任务。大部分的设置可以通过self.crawl
的参数去指定。def index_page(self, response)
接收一个response对象。response.doc
是一个pyquery
对象,它有一个类似jQuery
选择器一样的接口,去解析页面元素。def detail_page(self, response)
返回一个字典结果。这个结果默认会被写入resultdb
(结果数据库)。你可以通过复写on_result(self, result)
方法来按照你自己的需求处理结果。@every(minutes=24 * 60)
这个装饰器会告诉调度器,on_start
方法将会每天被调用。@config(age=10 * 24 * 60 * 60)
指定当self.crawl
爬取的页面类型为index_page
(当callback=self.index_page
)时的age参数的默认值。参数age
可以通过self.crawl(url, age=102460*60)
和crawl_config
来指定,直接在方法参数中指定具有最高的优先级。age=102460*60
告诉调度器抛弃10天内爬取过的请求。默认情况下,相同URL不会被爬取两次,甚至你修改了代码。对于初学者来说,第一次运行项目然后修改它,在第二次运行项目的情况非常常见,但是它不会再次爬行(阅读itag
了解解决方案)@config(priority=2)
标志着,detail page
将会被优先爬取。你可以通过点击绿色的run
按钮,一步一步的调试你的脚本。切换到follows
面板,点击play
按钮前进。
注意点 :
self.crawl
函数时必须加上validate_cert=False
保证能够爬取https,不然会报599,SSL 错误解决办法PhantomJS
,下载PhantomJS.exe
丢掉·python.exe
同路径下,通过添加参数fetch_type='js'
来启用此功能self.crawl由于链家网没有使用js生成数据,所以没有加上fetch_type='js'
,当我运行,得到了链家网首页 364条a标签的链接
获取需要url所在的xpath路径
在重新crawl方法,我们可以看出title和url的输出,说明没有问题
对于pyspider还有一个简介的方法就是通过css选择器来获取对应的css路径,从下面可以看出代码没有问题
对于入库需要写on_result
方法和初始化方法具体如下
不到半分钟,数据爬取完毕
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Created on 2019-07-21 17:08:14
# Project: lianjia
from pyspider.libs.base_handler import *
from lxml import etree
import pymysql
class Handler(BaseHandler):
crawl_config = {
}
def __init__(self):
db_config = {
'host': '', #ip
'user': '', #账号:不能用root的账号
'password': '',
'db': '',
'charset': 'utf8',
'port': 3306
}
self.db = pymysql.connect(**db_config)
self.cur = self.db.cursor()
# 创建表items
sql1 = 'create table if not exists items (url varchar(255) NOT NULL ,title VARCHAR(255) NOT NULL, price VARCHAR(255) NOT NULL, content mediumblob NOT NULL, Introduce mediumblob NOT NULL) '
self.cur.execute(sql1)
print('数据库创建成功')
@every(minutes=24 * 60)
def on_start(self):
# 通过迭代来不断的访问新的链接
for i in range(1,101):
self.crawl('https://dg.lianjia.com/ershoufang/{}'.format(i), callback=self.index_page,validate_cert=False)
@config(age=10 * 24 * 60 * 60)
def index_page(self, response):
xml = etree.HTML(response.text)
urls = xml.xpath('//ul[@class="sellListContent"]//li/a/@href')
# 获取每页的li中的url
print(urls) #列表
#for each in response.doc('a[href^="http"]').items():
#self.crawl(each.attr.href, callback=self.detail_page,validate_cert=False)
for url in urls:
self.crawl(url, callback=self.detail_page,validate_cert=False)
@config(priority=2)
def detail_page(self, response):
# 爬取对应的title,url, pricecontent和Introduce
return {
"url": response.url,
"title": response.doc('title').text(),
"price": str(response.doc('.price > .total').text()) + '万',
"content": response.doc('.base').text(),
"Introduce":response.doc('.baseattribute > .content').text()
}
@config(priority=2)
def on_result(self, result):
sql = 'insert into items(url,title,price,content,Introduce) values(%s, %s,%s,%s,%s)'
try:
if result['url']:
self.cur.execute(sql, (result['url'], result['title'],result['price'], result['content'],result['Introduce']))
except Exception as e:
self.db.rollback()
print(e)
else:
self.db.commit()
不到半分钟爬取了1146条数据,但是有的数据的重复的,应该用集合来去重