
本文共 8768 字,大约阅读时间需要 29 分钟。
文章目录
1 pyspider介绍
一个国人编写的强大的网络爬虫系统并带有强大的WebUI。采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器,任务监视器,项目管理器以及结果查看器。
功能强大的WebUI,包含脚本编辑器,任务监视器,项目管理器和结果查看器。
Pyspider框架:
多线程处理、去重处理、错误重试、结果监控、PyQuery提取、代码简洁、WebUI管理、JavaScript渲染
2 pyspider启动服务,进入WebUI界面
使用之前,先降低 tornado 版本(pyspider和jupyter要求的tornado版本有冲突)
pip install -i http://pypi.douban.com/simple --trusted-host pypi.douban.com tornado==4.5.3# 使用完在切换回去# pip install -i http://pypi.douban.com/simple --trusted-host pypi.douban.com tornado --upgrade
降低版本后,执行命令来启动服务器
pyspider或pyspider all
接下来
打开浏览器,在地址栏输入:http://localhost:5000/
即可打开pyspider的web UI界面
3 pyspider项目的创建
Project Name:任务的名字,可以任意填
Start URL(s):爬取任务开始的地址,这里我们填目标网址的url,也可以先不填

注意右侧,pyspider 已经帮我们生成了一段代码,代码如下所示:
4 应用例子1
from pyspider.libs.base_handler import *import pymongo# Handler 是 pyspider 爬虫的主类# 整个爬虫的功能只需要一个 Handler 即可完成class Handler(BaseHandler): headers= { 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Encoding':'gzip, deflate, sdch', 'Accept-Language':'zh-CN,zh;q=0.8', 'Cache-Control':'max-age=0', 'Connection':'keep-alive', 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36' } # 可以将本项目的所有爬取配置统一定义到这里 # Headers # Cookies crawl_config = { 'headers' : headers, #"user_agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", #"timeout": 120, #"connect_timeout": 60, #"retries": 5, "fetch_type": 'js', #"auto_recrawl": True, } # //数据库配置,用的monggodb client = pymongo.MongoClient(host='localhost',port=27017) db = client['trip'] # 填写第一个url地址,起始的url,start url 是要爬取的链接 # 点击run 后会先调用这个函数 # @every(minutes=24 * 60) 通知 scheduler(框架的模块) 每天运行一次 @every(minutes=24 * 60) def on_start(self): # self.crawl:爬取的主方法,被on_start调用,即可新建一个爬取请求 # 发起请求,把 Response 发给 index_page 函数,index_page将会接受response # validate_cert=False 解决证书报错 self.crawl('https://www.tripadvisor.cn/Attractions-g294211-Activities-c47-China.html', callback=self.index_page,validate_cert=False) # 爬取索引页 # 带http的链接 # @config(age=10 * 24 * 60 * 60) 设置任务的有效期限,在这个期限内目标爬取的网页被认为不会进行修改 @config(age=10 * 24 * 60 * 60) def index_page(self, response): ''' Parameters ---------- 参数为 Response 对象 response : TYPE DESCRIPTION. Returns ------- 将爬取的结果进行解析 生成新的爬取请求 ''' # 在 pyspider 中,内置了 response.doc 的 PyQuery 对象,让你可以使用类似 jQuery 的语法操作 DOM 元素。 # 默认是 a[href"="http ”],也就是说该方法解析了页面的所有链接 # 将 response 中 div.listing_title > a 标签拿到,循环每一个 a 标签 for each in response.doc('div.listing_info > div.listing_title > a').items(): # 再次发起请求,取出每一个a标签的连接,将结果返回给detail_page函数 # validate_cert=False 解决证书报错 self.crawl(each.attr.href, callback=self.detail_page,validate_cert=False) # 下一页 # next = response.doc('.paginatiaon.naw.next').attr.href # self.crawl(next , callback=self.index_page) # 爬取详情页 # 通过点击左边的->获取页面信息细节(包括url和title) # @config(priority=2) 设定任务优先级 @config(priority=2) def detail_page(self, response): url = response.url, title = response.doc('title').text(), name = response.doc('#HEADING').text(), paiming = response.doc('span.header_rating > div > a > span').text(), phonenum = response.doc('div.blEntry.phone > span:nth-child(2)').text(), dizhi = response.doc('div.detail_section.address.xh-highlight').text(), youwanshijian = response.doc('#taplc_attraction_detail_listing_0 > div.section.hours > div').text() # 最终将需要的数据作为一个 dict 对象返回,即为最终的抓取结果 return { "url":url, "title":title, "name":name, "paiming":paiming, "phonenum":phonenum, "dizhi":dizhi, "youwanshijian":youwanshijian } # 如果没有这个函数,抓取到的数据将默认存储到 resultdb 本地的数据库 # 结果存入数据库中 # 接受detail_page返回结果 def on_result(self,result): # 注意这里的if result:这句判断很重要,不然的会会报错,提示result是未定义类型的。 if result: self.save_to_mongo(result) # insert到mongo def save_to_mongo(self,result): if self.db['chinastrip'].insert(result): print('save to mongo',result)
5 应用例子2:爬取新闻标题
启动 PySpider
打开浏览器,在地址栏输入:http://localhost:5000/https://www.chinca.org/CICA/Memberdynamics/List?p=1



当 pyspider 连上 PhantomJS 代理后,你就能通过在 self.crawl 中添加 fetch_type=‘js’ 的参数,开启使用 PhantomJS 抓取。

再次运行

也可以配合原网页


https://www.chinca.org/CICA/Memberdynamics/List?p=1
https://www.chinca.org/CICA/Memberdynamics/List?p=2 https://www.chinca.org/CICA/Memberdynamics/List?p=3作如下修改
def __init__(self): # self.page = 1 self.totalpage = 5 self.base_url = 'https://www.chinca.org/CICA/Memberdynamics/List?p=' @every(minutes=24 * 60) def on_start(self): for i in range(1,self.totalpage+1): self.crawl(self.base_url+str(i), callback=self.index_page,fetch_type='js') ''' while self.page <= self.totalpage: self.crawl(self.base_url+str(self.page), callback=self.index_page,fetch_type='js') self.page += 1 '''

返回主页面
将程序设置为 运行状态

点击 run
后台在不断请求数据


5页内容


这个脚本里只是单纯的将结果打印在pyspider 的web ui中,并没有存到其它地方。
默认情况下,会把爬取到的结果存放到result.db这个sqilite数据库中,但是为了方便操作,我们将结果存放到mysql中。
6 Pyspider把抓取的结果存入mysql数据库
#!/usr/bin/env python# -*- encoding: utf-8 -*-# Created on 2021-02-01 10:26:51# Project: newimport pymysqlfrom pyspider.libs.base_handler import *class Handler(BaseHandler): # 连接数据库 def __init__(self): # self.page = 1 self.totalpage = 2 self.base_url = 'https://www.chinca.org/CICA/Memberdynamics/List?p=' self.db = pymysql.connect('localhost', 'root', '*****', '**', charset='utf8')#连接数据库 # 获得Cursor对象 cursor = self.db.cursor() cursor.execute("DROP TABLE IF EXISTS FUN_TEST") # 创建表 sql = """CREATE TABLE FUN_TEST ( title CHAR(255), url CHAR(255), from_ CHAR(255), date_ CHAR(255), content CHAR(255), Typesetting CHAR(255) )""" cursor.execute(sql) self.db.close() def save_in_mysql(self, title,url,from_,date_,content,Typesetting): try: self.db = pymysql.connect('localhost', 'root', '*****', '***', charset='utf8')#连接数据库 cursor = self.db.cursor() sql = 'INSERT INTO FUN_TEST(title,url,from_,date_,content,Typesetting) VALUES ("%s","%s","%s","%s","%s","%s")'% (title[0],url[0],from_[0],date_[0],content[0],Typesetting); print(sql) cursor.execute(sql) self.db.commit() print('插入成功') except Exception as e: # print(e) self.db.rollback() # 表示每天执行一次 @every(minutes=24 * 60) def on_start(self): for i in range(1,self.totalpage+1): self.crawl(self.base_url+str(i), callback=self.index_page,fetch_type='js') # 表示数据10天后就过期了 @config(age=10 * 24 * 60 * 60) def index_page(self, response): for each in response.doc('.kerconrtbor .clearfix a').items(): self.crawl(each.attr.href, callback=self.detail_page) @config(priority=3) def detail_page(self, response): title = response.doc('title').text(), url= response.url, from_ = response.doc('.releasetime > span:nth-child(1)').text(), date_ = response.doc('div.industry-news > div:nth-child(4) > span').text(), content = response.doc('.industry-news > p:nth-child(1)').text(), Typesetting = response.doc('.releasetime > span:nth-child(2)').text() self.save_in_mysql(title,url,from_,date_,content,Typesetting) return { "title": response.doc('title').text(), "url": response.url, "from_":response.doc('.releasetime > span:nth-child(1)').text(), "date_": response.doc('#aspnetForm > div.ermainwih > div.ermain > div.ercon.clearfix > div.industry-news > div:nth-child(4) > span').text(), "content": response.doc('#aspnetForm > div.ermainwih > div.ermain > div.ercon.clearfix > div.industry-news > p:nth-child(5)').text(), "Typesetting": response.doc('.releasetime > span:nth-child(2)').text() }
再次运行
结果

发表评论
最新留言
关于作者
