理论部分:
一、爬虫使用场景分类
- 通用爬虫:
抓取系统重要组成部分。抓取的是一整张页面数据-
聚焦爬虫:
是建立在通用爬虫的基础之上。抓取的是特定的局部内容- 增量式爬虫:
检测网站中数据更新的情况。只会抓网站中最新更新出来的数据
二、爬虫的矛与盾- 反爬机制:
门户网站,可以通过制定相应的策略或技术手段,防止爬虫程序进行网站数据的爬取- 反反爬策略
爬虫程序 可以通过制定相关的策略或技术手段,破解门户网站中具备的反爬机制
从而获取门户端网页源码- robots.txt 协议
君子协议 规定了网页中那些数据可以被爬虫爬取
三、浏览器相关内容- http协议(概念) 就是服务器和客户端进行数据交互的一种形式
- 常用请求头信息
- http协议(概念) 就是服务器和客户端进行数据交互的一种形式
- robots.txt 协议
- 反反爬策略
- 反爬机制:
- 增量式爬虫:
-
User-Agent : 请求载体的身份标识
-
Connection : 请求完毕后 ,是断开连接还是保持连接
- 常用响应头信息
-
Content-type : 服务器响应会客户端的数据类型
- https 安全的超文本传输协议
- 加密方式
-
对称密钥加密
-
非对称密钥加密
-
证书密钥加密
五、实战:- 爬虫模块 模块
-
urllib 模块(太古老,不学习,有更好的)
-
requests 模块
- requests 模块
-
介绍:
python 中原生的一款基于网络请求的模块,功能非常强大,简单便捷,效果极高
作用: 模拟浏览器发送请求 -
如何使用
- 指定url
- 发送请求
- 获取响应数据
- 持久化存储
-
环境安装:
pip install requests -
实战编码:
UA 伪装 :
headers = {“User-Agent”:‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36’}- 需求: 1、 爬取搜狗首页网页数据 2、 爬取百度简易词条对应的搜索结果页面(简易的网页采集器) 3、 获取百度翻译 4、 爬取豆瓣电影分类排行榜 https://movie.douban.com/中的电影详情数据 5、 爬取肯德基餐厅查询 http://www.kfc.com.cn/kfccda/index.aspx指定的餐厅 6、 爬取国家药品监督管理总局中基于中华人民共和国化妆品生产许可证相关数据:http://scxk.nmpa.gov.cn:81/xk/
-
六、聚焦爬虫:爬取页面中指定页面内容
- 编码流程
- 指定url
- 发送请求
- 获取响应数据
- 数据解析
- 持久化存储
- 数据解析分类
- 正则
- bs4
- xpath(*)
- 数据解析原理概述:
- 解析局部的文本内容都会在标签之间或标签对应的属性中进行存储
- 1、进行指定标签的定位
- 2、标签或标签对应的属性中存储的数据值进行提取(解析)
response.text: 获取网页源码
response.json(): 获取json数据的二进制文本
response.content: 获取二进制文本
- 正则解析:
ex = “正则表达式”
正则书写技巧:
跨越的内容 用 .? 取缔
提取的内容 用 (.?) 取缔
然后就是正规提取,标签之间要对应
re.find_all(ex,data,re.S)
- bs4进行数据解析:
- 数据解析的原理:
- 标签定位
- 提取标签、标签属性中存储的属性值
- bs4数据解析原理:
- 1 实例一个 BeautifulSoup 对象,并且将网页源码数据加载到该数据中
- 2 通过调用BeautifulSoup 对象中相关属性或者方法进行标签定位和数据提取
soup.find_all()
soup.find()
soup.select()
- 3 获取标签中的文本数据:
soup.find().text/string/get_text()
text/get_text(): 可以获取某个标签中所有的文本内容
string: 只能获取本标签中文本内容
- 4 获取标签中的属性
soup.a[“href”]
- 环境安装:
- pip install bs4
- pip install lxml
- xpath : 最常用且最便捷高效的一种解析方式。通用性
- xpath解析原理:
- 1.实例化一个etree的对象,且需要将解析的页面源码数据加载到该对象中
- 2.调用etree 对象中的xpath 方法结合着xpath 表达式实现标签的定位和内容的捕获
- 环境的安装
- pip install lxml
- 如何实例化一个etree 对象:from lxml import etree
- 1、将本地中的html文档源码数据加载到etree 对象中:
etree.parse(filepath)
- 2、可以将互联网上获取的源码数据加载到该对象中
etree.HTML(“page_text”)
- xpath(‘xpath表达式’)
- xpath表达式:
- /: 表示从根节点开始定位。表示是一个层级
- //: 表示多个层级,可以表示从任意位置开始定位
- 属性定位://a[@class=‘song’]
- 属性定位: //p[3] # 索引是从1 开始的
- 获取文本:
/text() 获取直系文本
//text() 获取直系和非直系文本
- 取属性
p/@attrName
乱码部分解决方案:
1.手动设置响应数据的编码方式
response.encoding = ‘utf-8’
page_text = response.text
2.堆乱码部分重新编码再解码
img_name = img_name.encode(‘iso-8859-1’).decode(‘gbk’)
7.人人网模拟登录:
步骤:
1.首先在网页模拟登录, (打开检查 ,点击 network ,钩上preserver log 选项)
2.点击登录
3.会检测一个 login 包:是一个 post 请求,登录之后的页面,post 参数 需要一个验证码(提前获取)
# 验证登陆成功的两种方式
1. 获取相应数据后,保存,打卡
2. 发送请求后,返回结果为 200, 则表示登录成功
爬取当前用户相关用户信息:
https协议特性: 无状态
无法请求对应的页面数据的原因:
第二次基于个人主页页面请求时,服务器地址并不知道此请求是基于登录状态下的请求
cookie: 用来让服务器记录客户端相关状态
手动处理:通过抓包工具获取cookie 值,将封装到headers 中(不建议)
自动处理:
- cookie值的来源: 模拟登录post 请求后,有服务器创建
session 会话对象:
作用:1.可以进行请求的发送
2.如果请求过程中产生了 cookie ,则将该 cookie 自动存储 在session 对象中
步骤:
1.创建一个session 对象:session = resquests.Session()
2.使用session 对象进行模拟登录post 请求发送(cookie 就会被存储于 session 对象中)
3.session 对个人主页进行get 请求发送(携带了 cookie)
8.代理IP
代理: 破解封IP这种反爬机制
什么是代理: 代理服务器
代理的作用:
- 破解自身IP 访问的限制
- 隐藏自身真实IP
代理相关网站:
- 快代理
- 西祠代理
- www.goubanjia.com
代理IP的类型:
- http: 应用到http 协议对应的url 中
- https: 应用到https 协议对应的url 中
代理ip匿名度:
- 透明: 服务器知道了此次请求使用了代理,也知道请求对应的真实ip
- 匿名: 知道使用了代理,不知道真实IP
- 高匿: 不知道使用了代理,不知道真实IP
使用:
response = requests.get(url = url,headers = headers,proxies = {‘http’:‘175.42.128.37’}).text
9.线程池
高性能的异步爬虫
目的: 在爬虫中使用异步实现高性能的的数据爬去操作
异步爬虫的方式:
- 多线程,多进程(不建议):
好处:可以为相关阻塞操作单独开启线程或进程,阻塞操作既可以异步执行
弊端:无法无限制的的开启多线程或多进程
- 线程池,进程池(适当的使用):
好处: 可以降低系统对进程或线程的创建和销毁的一个频率,从而很好的降低系统的开销
弊端: 池中线程或进程的数量是由上线的
使用:
from multiprocessing.dummy import Pool
…
pic_request.map(func,iterable)
pic_request.close()
pic_request.join()
- 单线程 + 异步爬虫 (推荐):
event_loop:时间循环,相当于一个无限循环我们可以把一些函数注册到这个时间循环上
当满足某些条件时,函数就会被循环执行。
coroutine :协程对象,我们可以将协程对象注册到事件循环中,他会被事件循环调用。
我们可以使用 async 关键字来定义一个方法,这个方法调用时不会立即被执行
而是返回一个协程对象
task:任务 , 他是对协程对象的进一步封装,包含了任务的各个状态.通过 loop.create_task©创建
future: 它代表了将来执行 还未执行 的任务,实际上和task 没有本质区别,通过 asyncio.ensure_future© 创建
async : 定义了一个协程
await : 用来挂起阻塞方法的执行
操作:
import asyncio
async def request(url):
print("正在发送请求 "+ url)
await asyncio.sleep(1)
print("请求成功")
return url
# 返回一个携程对象
c = request("http://www.baidu.com")
# # 创建时间循环
# loop = asyncio.get_event_loop()
# # 调用协程对象
# loop.run_until_complete(c)
# # 通过task 任务对象 ,调用协程对象
# loop = asyncio.get_event_loop()
# # 创建task 任务对象
# task = loop.create_task(c)
# print(task)
# # 调用task任务
# loop.run_until_complete(task)
# print(task)
# # 通过调用 future 任务对象, 调用携程对象
# loop = asyncio.get_event_loop()
# # 创建 future 任务对象
# task = asyncio.ensure_future(c)
# print(task)
# # 调用task 任务对象
# loop.run_until_complete(task)
# print(task)
操作任务列表:
import asyncio
from time import time
start = time()
async def request(url):
print("开始请求 "+ url)
# 注意异步代码中 ,不能使用同步代码
await asyncio.sleep(2)
print("开始请求 "+ url)
urls = [
"http://www.baidu.com",
"http://www.taobao.com",
"http://www.jingdong.com"
]
# 协程对象的任务列表
tasks = []
for url in urls:
c = request(url)
task = asyncio.ensure_future(c)
tasks.append(task)
# 创建事件循环
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print("执行时间 "+ str(time()-start))
异步的requests 请求的发送:
async with aiohttp.ClientSession() as session:
async with await session.get(url = url,headers = headers) as response :
page_source = await response.text()
print(page_source)
- 请求的发送
session.get(url = url ,headers = headers,params = params)
session.post(url = url,headers = headers ,data = data)
ip 伪装: proxy = "http://ip:port"
- 响应数据的获取:
- text(): 返回字符串形式的响应数据
- read(): 返回二进制形式的响应数据
- json(): 返回json 形式的相应数据
注意: 在响应数据之前,一定要加 await ,获取响应数据是个延迟操作
10.selenium 模块的基本使用
- 问题: selenium 模块 和 爬虫之间的具有怎样的关联?
- 便捷的获取网站中动态加载的数据
- 便捷的实现模拟登录
- 什么是selenium 模块:
- 基于浏览器自动化的一个模块
- selenium 使用流程:
- 环境安装: pip3 install selenium
- 下载一个浏览器驱动程序(谷歌浏览器):
- 下载路径:http://chromedriver.storage.gooleapis.com/index.html
- 驱动程序和浏览器的映射关系: https://www.cnblogs.com/feifei-cyj/p/7506666.html
- 配置 chromedriver 环境到 python 中(可以不配置,实例化对象的时候需要指定chromedriver 的路径)
- 下载好chromedriver
- cp chromedriver /usr/local/bin
- 验证是否安装成功 chromedriver -v
- 实例化一个浏览器对象
导入 from selenium import webdriver
bro = webdriver.Chrome()
- 编写基于浏览器自动化的操作代码
- 发起请求: get(url)
- 标签定位: find系列方法
- 标签交互: send_keys("***")
- 执行js程序: execute_script(“jsCode”)
window.scrollTo(0,document.body.scrollHeight) # 滑动 ,向下滑动屏幕
- 前进,后退: forward() back()
- 关闭浏览器 和 驱动程序: quit()
- 获取当前页面截图
bro.save_screenshot(‘百度.png’)
- 打印当前页面的标题
print(bro.title)
- 获取网页源码
bro.page_source
- 获取标签文本信息
element.text
- 获取标签属性值
element.get_attribute(“属性名”)
- 获取当前页面的文档句柄列表
window_list = bro.window_handles
- 切换句柄
bro.switch_to.window(window_list[0])
- 切换frame
bro.switch_to.frame(iframe)
- 窗口最大化
bro.maximize_window()
- 设置窗口
bro.set_window_size()
- 截图
bro.save_screenShot()
- 关闭
close() : 关闭当前
quit() : 关闭所有
- selenium处理iframe
- 如果定位的标签存在于iframe 标签之中,则必须使用switch_to.frame(id)
- 返回上一层 frame
bro.switch_to.parent_frame()
- 返回主文档
bro.switch_to.default_content()
- 动作链(拖动):from selenium.webdriver import ActionChains
- 实例化一个动作链对象: action = ActionChains(bro)
- click_and_hold(div): 长按且点击操作
- move_by_offset(x,y)
- perform() 让动作立即执行
- action.release() 释放动作链对象
- 鼠标右击
actionChains(bro).context_click(element).perform()
- 鼠标拖拽
actionChains(bro).drag_and_drop(element1,element2).perform()
- 注意: 每执行一次具体的程序操作尽量让其睡两秒钟
11.无头浏览器
# 无头浏览器设置
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument(’–headless’)
chrome_options.add_argument(’–disable-gpu’)
bro = webdriver.Chrome(
executable_path = ‘/Users/macos/chromeDriver/chromedriver’,
chrome_options = chrome_options,
)
12.规避检测
* 规避检测
from selenium.webdriver import ChromeOptions
options = ChromeOptions()
options.add_experimental_option(‘excludeSwitches’,[‘enable-automation’])
bro = webdriver.Chrome(
executable_path = ‘/Users/macos/chromeDriver/chromedriver’,
options= options
)
综上: 粘贴复制即可, 哈哈
# 无头浏览器
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 规避检测
from selenium.webdriver import ChromeOptions
options = ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
bro1 = webdriver.Chrome(chrome_options= chrome_options,options=options)
13.scrapy 框架
- 指令的简单使用:
- 创建一个工程 : scrapy startproject xxxPro
- cd 到项目工程下 : cd xxxPro
parse函数中的response 是相应数据,可以直接进行xpath解析
response.xpath().extract_first() : 列表中只有一个元素
response.xpath().extract() : 列表中有多个元素
- 创建爬虫文件: scrapy genspider xxx www.xxx.com
- 执行工程: scrapy crawl xxx
不打印配置信息:
方法一: 直接执行scrapy crawl xxx --nolog(不推荐)
方法二: 在setting 加上 LOG_LEVEL = “ERROR”
然后执行 scrapy crawl xxx
- settings :
设置 UA 伪装
设置 robots 协议 (放开注释即可)
设置 管道 (放开注释 即可)
设置 LOG_LEVEL = “ERROR” (只有ERROR的信息,才被打印)
- 持久化存储
- 基于终端指令
- 要求: 只可以将parse方法的返回值存储到本地的文本文件中
- 注意: 持久化对应的文本文件类型只可以为: json , jsonlines ,jl , csv, xml
- 指令: scrapy crawl xxx -o filepath
注意: 将parse 函数中的数据封装到 一个列表(包含多个字典)中,最后,将列表return
- 好处: 简介高效便捷
- 缺点: 局限性比较强(数据只可以存储到指定后缀的文本文件中)
- 基于管道
- 编码流程:
- 数据解析
- 在item 中定义相关属性
- 将解析的数据类型存储到 item 类型的数据
- 将 item 类型的对象提交给管道进行持久化存储操作(yield item)
- 在管道类的process_item中将接受的item对象存储的数据进行持久化存储操作
打开/关闭文件:
在 process_item 类中重写:
fp = None
open_spider(self,spider): # 该函数只在开始时执行一次
self.fp = open(filename,'w',encoding = 'utf-8')
process_item(self.spider):...
close_spider(self,spider): # 该函数只在最后执行一次
self.fp.close()
- 在 settings 开启管道
- 好处: 通用性强
- 基于mysqlPipeLine 管道的存储
class MysqlPipeline:
conn = None
cursor = None
def open_spider(self,spider):
print("开始爬取")
self.conn = pymysql.Connect(
host='127.0.0.1',
port=3306,
user='root',
db='famousTalk',
password='034312',
charset='utf8',
)
def process_item(self, item, spider):
self.cursor = self.conn.cursor()
try:
tell = item['t']
sql = """INSERT INTO first(talk)
VALUES ('%s')"""%(tell)
self.cursor.execute(sql)
self.conn.commit()
except Exception as e:
print(e)
self.conn.rollback()
return item
def close_spider(self,spider):
print("爬取完毕")
self.cursor.close()
self.conn.close()
- 面试题 : 将爬取到的数据一份存储到本地一份存储到数据库,如何实现?
- 管道文件中的一个管道类对应的是将数据存储到一种平台
- 爬虫文件提交的item只会给管道文件中的一个执行的管道类接收
- process_item 中的return item 表示将item 传递给下一个要被执行的管道
- 全站爬取:
- 实现创建一个 URL 模版
- 全站爬取:
if self.page_num <= 5:
new_url = format(self.url % self.page_num)
self.page_num += 1
yield scrapy.Request(url = new_url,callback=self.parse)
- scrapy 的五大组件
- 引擎(Scrapy)
用来处理整个系统的数据流处理,触发事务(框架的核心)
- 调度器(Scheduler)
用来接收引擎发过来的请求,压入队列中,并在引擎再次请求的时候返回,可以想象成一个
URL(抓取网页网址或者是链接)优先队列,有他来决定下一个要抓取的网址是什么,同时
取出重复网址
- 下载器(Downloader)
用于下载网页内容,并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效)
的异步模型上的
- 爬虫(Spiders)
爬虫是主要干活的,用于从特定的网页中提取自己需要的信息。即所谓的实体(Item)。用户
也可以从中提取出来链接,让scrapy 继续抓取下一个页面
- 项目管道(Pipeline)
负责处理爬虫从网页中提取的实体,主要的功能是持久化实体,验证实体的有效性,清除不需要
的信息。当网页被爬虫解析后,将被发送到项目管道,并将过几个特定的次序处理数据
- 请求传参(深度爬取)
- 使用场景:如果爬取解析的数据不在同一张页面中。(深度爬取)
- 需求: 爬取boss 的岗位名称,岗位描述
- 再次定义解析函数
def detail_parse(self,response):
item = response.meta['item']
...
yield item
def parse(self,response):
# 数据解析
item = XXXItem()
# 将item传递给detail_parse
yield scrapy.Requests(url = new_url,
callback=detail_parse,
meta = {'item':item}
)
- 图片的下载
- 在爬虫文件中最主要的就是将 图片的的src属性进行提交
- 设置图片管道
from scrapy.pipelines.images import ImagesPipeline
# ImagesPipline 专门用于文件下载的管道类,下载过程支持异步和多线程
import scrapy
class ImgsZhanzhangproPipeline(ImagesPipeline):
item = None
def get_media_requests(self,item,info):
# 对item类中读片进行发送请求操作
self.item = item
yield scrapy.Request(item['src'])
def file_path(self, request, response=None, info=None, *, item=item):
# 定制图片的名称
# url = request.url
# file_name = url.split('/')[-1]
# return file_name
return item['name']
def item_completed(self, results, item, info):
# 该返回值会传递给下一个即将被执行的管道类
return item
# 设置图片下载目录
# 在settings设置图片存储目录
IMAGES_STORE = './imgs'
- 下载中间件
- 位置:引擎与下载器之间
- 作用: 批量拦截到整个工程所有的请求和响应
- 拦截请求:
- UA 伪装:process_requests
UA池:
user_agent_list = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
"(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
]
在中间件中设置:
request.headers['User-Agent'] = random.choice(self.user_agent_list)
- 代理 IP:process_exception:return request
PROXY_http = [
'153.180.102.104:80',
'195.208.131.189:56055',
]
PROXY_https = [
'120.83.49.90:9000',
'95.189.112.214:35508',
]
if request.url.split(":")[0] == "http":
request.meta['proxy'] = "http://"+random.choice(self.PROXY_http)
else:
request.meta['proxy'] = "https://"+random.choice(self.PROXY_https)
return request
- *** 在settings 中 注释开 下载中间件的管道
- 拦截响应:
- 篡改响应数据,响应对象
- 案例: 动态加载ajax 请求
由于请求是动态加载的,所有配合selenium 使用
1.在 process_response 中设置,导入 HtmlResponse:
def process_response(self, request, response, spider):
# 用于拦截特定的响应
bro = spider.bro
if request.url in spider.model_urls:
# 篡改响应数据
bro.get(request.url)
page_source = bro.page_source
response = HtmlResponse(url=request.url, body=page_source, encoding='utf-8', request=request)
return response
else:
return response
2.在爬虫文件中
- 构造 selenium 对象,
- 创建关闭方法:
def close(self,spider):
# 关闭 selenium 对象
3.在管道文件中
注释开 下载中间件
- CrawlSpider: 类 ,Spider的一个字类
- 全站数据爬取的方式
- 基于spider : 手动请求
- 基于 CrawlSpider: 使用 rules
- CrawlSpider的使用
- 创建一个工程
- cd 到工程目录下
- 创建爬虫文件: scrapy genspider -t crawl 爬虫文件 url
-
rules = (
Rule(LinkExtractor(allow=r'/page/\d+/'), callback='parse_item', follow=True),
Rule(LinkExtractor(allow=r'/author/[a-zA-Z-]+'), callback='detail_parse_item', follow=True),
)
rulse(规则解析器):
将提取器提取的链接进行指定规则(callback)解析
Rule(链接提取器):
根据制定规则的allow 进行指定链接的提取
注意: 使用xpath 时不能出现 body 标签
- 深度爬取
在爬虫文件,需要多个解析函数,需要使用多个item 进行提交
在items文件中
class QuotesproItem(scrapy.Item):
author = scrapy.Field()
quote = scrapy.Field()
class DetailuotesproItem(scrapy.Item):
detail_author = scrapy.Field()
detail_desc = scrapy.Field()
在pipelines文件中
if item.__class__.__name__ =='QuotesproItem':
author = item['author']
quote = item['quote']
else:
detail_desc = item['detail_desc']
detail_author = item['detail_author']
- 分布式爬虫:(暂时用不到,此处略去 10000 字)
- 增量式爬虫:
- 概念:检测网站数据的情况,只会爬取网站最新更新来的数据
- 分析:
- 指定url
- 基于CrawLSpider获取其他网页链接
- 基于Rule 将其他代码链接进行请求
- 从每个页码对应的页面源码中解析出每个详情页的url
- 核心:
- 检测电影详情页的url 之前有没有请求过
- 将爬取的电影详情页的url 存储
- 存储到redis 中 set 的数据结构
- 对详情页的url 发送请求,然后解析出电影的名称和简介
- 进行持久化存储
- scarpy 如何进行模拟登录
- 为什么要模拟登录: 有的网站需要登录在进行爬取
- 模拟登录思路:
- 使用 selenium: 太 low (虽然我没研究)
- 使用Requests cookies 进行请求,绕过登录
- 使用Requests 发送post 请求 将网站携带到post的请求进行登录
- 携带cookies进行模拟登录
- 优点: cookie 过期时间很长,登录一次后不用担心登录问题
- 操作:
- 创建一个scrapy项目,修改配置
- 创建爬虫文件
- 重写start_requests方法(直接粘贴复制过去,改一下cookie值)
def start_requests(self):
# 登录之后用 chrome 的 debug 工具从请求中获取的 cookies
cookiesstr = "anonymid=k3miegqc-hho317; depovince=ZGQT; _r01_=1; JSESSIONID=abcDdtGp7yEtG91r_U-6w; ick_login=d2631ff6-7b2d-4638-a2f5-c3a3f46b1595; ick=5499cd3f-c7a3-44ac-9146-60ac04440cb7; t=d1b681e8b5568a8f6140890d4f05c30f0; societyguester=d1b681e8b5568a8f6140890d4f05c30f0; id=972990680; xnsid=404266eb; XNESSESSIONID=62de8f52d318; jebecookies=4205498d-d0f7-4757-acd3-416f7aa0ae98|||||; ver=7.0; loginfrom=null; jebe_key=8800dc4d-e013-472b-a6aa-552ebfc11486%7Cb1a400326a5d6b2877f8c884e4fe9832%7C1575175011619%7C1%7C1575175011639; jebe_key=8800dc4d-e013-472b-a6aa-552ebfc11486%7Cb1a400326a5d6b2877f8c884e4fe9832%7C1575175011619%7C1%7C1575175011641; wp_fold=0"
cookies = {i.split("=")[0]:i.split("=")[1] for i in cookiesstr.split("; ")}
# 携带 cookies 的 Request 请求
yield scrapy.Request(
self.start_urls[0],
callback=self.parse,
cookies=cookies
)
- 运行爬虫文件(其实就是那么简单,但是我喜欢这种方式,实用)
- 查看cookies 传递过程
在 settings 配置中加 COOKIES_DEBUG = True
- 使用Requests 发送post 请求 模拟登录
- 操作:
- 创建项目
- 创建爬虫文件
- 发送data 数据
def parse(self, response):
# request header
postData = {
'ck': '',
'name': '****', # 用户名
'password': '****', # 密码
'remember': 'false',
'ticket': ''
}
return [FormRequest.from_response(
response,
formdata = postData,
callback = self.after_login,
dont_filter = True)]
- 写 after_login 方法 进行数据解析
- 执行爬虫文件
- 总结: 先使用 cookie ,不行是在使用 FormRequest