爬虫实操
内容概要
- requests 模块
- 简易爬取代码
- 进行动态爬取
- 乱码问题
- 反爬机制之身份识别(UA检测)
- 浏览器抓包工具
- 请求载体的身份认证
- 解决
- 动态加载数据的爬取
- 局部 & 全局
- 解决
内容详细
requests 模块
1、简易爬取代码
爬虫中基于网络请求的模块
用于模拟浏览器上网,向网站发起请求资源
有 get 方法和 post 方法请求
返回的是一个 response 对象,可以使用 response.text 等方式获取数据
import requests
url = "https://www.sogou.com/"
response = requests.get(url=url)
page_text = response.text
with open(r'./sougou.html', 'w', encoding='utf-8') as f:
f.write(page_text)
print('保存成功!')
2、进行动态爬取
# 先获取用户想查去的关键字
# 获取后的 url 地址是 : https://www.sogou.com/sogou?query=jay
# 只需要把关键字添加到 query= 的值中即可
keywork = input('enter a keywork')
url = 'https://www.sogou.com/web'
params = {
'query': keywork
}
response = requests.get(url=url,params=params)
page_text = response.text
file_name = keywork+'.html'
with open(file_name, 'w', encoding='utf-8') as f:
f.write(page_text)
print(保存成功)
乱码问题
有些网站的编码并不是 utf-8 ,保存数据使用 utf-8 编码会出现乱码问题
解决方法: 保存文件之前修改 response 对象的 encode 属性把数据编码为 utf-8 格式就可以解决
#携带了请求参数的url,如果想要爬取不同关键字对应的页面,我们需要将url携带的参数进行动态化
#实现参数动态化:
params = {
'query':keyWord
}
url = 'https://www.sogou.com/web'
#params参数(字典):保存请求时url携带的参数
response = requests.get(url=url,params=params)
#修改响应数据的编码格式
#encoding返回的是响应数据的原始的编码格式,如果给其赋值则表示修改了响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text
fileName = keyWord+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(fileName,'爬取完毕!!!')
反爬机制之身份识别(UA检测)
1、浏览器抓包工具
按 F12 可以调出检查工具
点击 network ,再刷新一下浏览器(重新请求数据),即可获取抓包工具抓取到的数据包
response 是数据包申请到的内容
2、请求载体的身份认证
请求载体:浏览器的搜索申请和 requests 发出的申请都属于请求载体
身份认证:在抓包工具中可以找到 user-agent 的请求头数据,用作身份识别
处理乱码后,页面显示【异常访问请求】导致请求数据的缺失。
异常的访问请求
网站后台已经检测出该次请求不是通过浏览器发起的请求而是通过爬虫程序发起的请求。(不是通过浏览器发起的请求都是异常请求)
网站的后台是如何知道请求是不是通过浏览器发起的呢?
是通过判定请求的请求头中的user-agent判定的
什么是User-Agent
请求载体的身份标识
什么是请求载体:
浏览器
浏览器的身份标识是统一固定,身份标识可以从抓包工具中获取。
爬虫程序
身份标识是各自不同
3、反反爬策略
# 第二种反爬机制:
UA检测:网站后台会检测请求对应的User-Agent,以判定当前请求是否为异常请求。
# 反反爬策略:
UA伪装:被作用到了到部分的网站中,日后我们写的爬虫程序都默认带上UA检测操作。
# 伪装流程:
从抓包工具中捕获到某一个基于浏览器请求的User-Agent的值,将其伪装作用到一个字典中,将该字典作用到请求方法(get,post)的headers参数中即可。
在用 requests 发起 get 申请之前先定义 header 变量,存储 user-agen 的请求头信息
get 请求中把 headers 变量当作关键字参数 headers 的值传入即可
keywork = input('enter a keywork')
url = 'https://www.sogou.com/web'
params = {
'query': keywork
}
# UA 伪装:注意,复制身份识别信息时要把 user-agent 也复制进去,而且 headers 得是一个字典,与 params 一样
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
}
response = requests.get(url=url,params=params,headers=headers)
page_text = response.text
file_name = keywork+'.html'
with open(file_name, 'w', encoding='utf-8') as f:
f.write(page_text)
print(保存成功)
动态加载数据的爬取
使用 requests 模块获取的数据并不一定每次都所见即所得,有些网页(如豆瓣电影)的数据是动态获取的,即它们的每个数据都是通过另外的 url 地址二次请求而来的,在首页地址 url 申请不到想要的数据
1、动态加载数据
什么叫动态加载的数据?
有些数据不是通过浏览器地址栏中的 url 请求到的数据,而是通过其它请求请求到的,那么这些通过其它请求获取到的数据就是动态加载的数据
如何检测网页是否存在动态加载数据
# 基于抓包工具进行局部搜索
在当前网页中打开抓包工具,捕获到地址栏中的 url 对应的数据包,在该数据包的 response 选项卡搜索我们想要爬取的数据,如果搜索到了结果表示数据不是动态加载的,没搜索到表示数据是动态加载的(其它请求获取来的数据)
2、局部搜索 & 全局搜索
3、解决
- 如果数据为动态加载,那么我们如何捕获到动态加载的数据?
- 基于抓包工具进行全局搜索。
- 定位到动态加载数据对应的数据包,从该数据包中就可以提取出
- 请求的url
- 请求方式
- 请求携带的参数
- 看到响应数据
url = 'https://movie.douban.com/j/chart/top_list'
params = {
'type': '5',
'interval_id': '100:90',
'action': '',
'start': '10',
'limit': '50',
}
response = requests.get(url=url,params=params,headers=headers)
#.json()将获取的字符串形式的json数据序列化成字典或者列表对象
page_text = response.json()
#解析出电影的名称+评分
for movie in page_text:
name = movie['title']
score = movie['score']
print(name,score)
思考
思考:基于抓包工具进行全局搜索不一定可以每次都能定位到动态加载数据对应的数据包?
原因:如果动态加载的数据是经过加密的密文数据。
分页数据的爬取操作
# 爬取肯德基的餐厅位置数据
url:http://www.kfc.com.cn/kfccda/storelist/index.aspx
分析:
1.在录入关键字的文本框中录入关键字按下搜索按钮,发起的是一个ajax请求
当前页面刷新出来的位置信息一定是通过ajax请求请求到的数据
2.基于抓包工具定位到该ajax请求的数据包,从该数据包中捕获到:
请求的url
请求方式
请求携带的参数
看到响应数据
爬取第一页
#爬取的是第一页的数据
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
data = {
'cname': '',
'pid': '',
'keyword': '北京',
'pageIndex': '1',
'pageSize': '10',
}
#data参数是post方法中处理参数动态化的参数
response = requests.post(url=url,headers=headers,data=data)
page_text = response.json()
for dic in page_text['Table1']:
title = dic['storeName']
addr = dic['addressDetail']
print(title,addr)
爬取多页
#爬取多页
#爬取的是第一页的数据
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
for page in range(1,9):
data = {
'cname': '',
'pid': '',
'keyword': '北京',
'pageIndex': str(page),
'pageSize': '10',
}
#data参数是post方法中处理参数动态化的参数
response = requests.post(url=url,headers=headers,data=data)
page_text = response.json()
for dic in page_text['Table1']:
title = dic['storeName']
addr = dic['addressDetail']
print(title,addr)