爬虫之基本操作篇
2.爬虫基本流程
1、发起请求
使用http库向目标站点发起请求,即发送一个Request
Request包含:请求头、请求体等
2、获取响应内容
如果服务器能正常响应,则会得到一个Response
Response包含:html,json,图片,视频等
3、解析内容
解析html数据:正则表达式,第三方解析库如Beautifulsoup,pyquery等
解析json数据:json模块
解析二进制数据:以b的方式写入文件
4、保存数据
数据库
文件
2.1请求与响应
#http协议:
http://www.cnblogs.com/linhaifeng/articles/8243379.html
#Request:
用户将自己的信息通过浏览器(socket client)发送给服务器(socket server)
#Response:
服务器接收请求,分析用户发来的请求信息,然后返回数据(返回的数据中可能包含其他链接,如:图片,js,css等)
#ps:
浏览器在接收Response后,会解析其内容来显示给用户,而爬虫程序在模拟浏览器发送请求然后接收Response后,是要提取其中的有用数据
3.jupyter的基本使用
- 什么是anaconda
- 是一个基于数据分析+机器学习的集成环境。
- 什么是jupyter(超级终端)
- 是anaconda中的一个基于浏览器可视化的编码工具
- 在指定目录下启动终端:录入jupyter notebook指令开辟指定的服务。
cell的两种模式
makedown 兼容笔记 笔记的编写
code编写代码
运行会开辟一块内存空间
然后就可以执行寻找变量对应的内存空间的数值
快捷键
插入cell:a,b
删除cell:x
执行cell:shift+enter
tab:自动补全
切换cell的模式:y,m
打开帮助文档:shift+tab
补充 http和https
是遵循的一种通讯协议 进行字节 字符串的传输
https 内布绒使用ssl加密 使用ca证书 防止黑客劫持
数据解析 爬去的数据进行筛选
达到对应ajax的url请求 xhr标签
4.requests模块
需要环境的安装:pip install requests
#1、请求方式:
常用的请求方式:GET,POST
get进行页面的获取 post用于搜索框查询和提交数据 然后post返回的响应数据需要使用json序列化
其他请求方式:HEAD,PUT,DELETE,OPTHONS
ps:用浏览器演示get与post的区别,(用登录演示post)
post与get请求最终都会拼接成这种形式:k1=xxx&k2=yyy&k3=zzz
post请求的参数放在请求体内:
可用浏览器查看,存放于form data内
get请求的参数直接放在url后
#2、请求url
url全称统一资源定位符,如一个网页文档,一张图片
一个视频等都可以用url唯一来确定
url编码
https://www.baidu.com/s?wd=图片
图片会被编码(看示例代码)
网页的加载过程是:
加载一个网页,通常都是先加载document文档,
在解析document文档的时候,遇到链接,则针对超链接发起下载图片的请求
#3、请求头
User-agent:请求头中如果没有user-agent客户端配置,
服务端可能将你当做一个非法用户
host
cookies:cookie用来保存登录信息
一般做爬虫都会加上请求头 来进行UA检测的反反爬策略
#4、请求体
如果是get方式,请求体没有内容
如果是post方式,请求体是format data
ps:
1、登录窗口,文件上传等,信息都会被附加到请求体内
2、登录,输入错误的用户名密码,然后提交,就可以看到post,正确登录后页面通常会跳转,无法捕捉到post
-
是一个基于网络请求的模块。
-
作用:模拟浏览器发起请求
-
分析requests的编码流程:
-
指定url 发起了请求 获取响应数据 持久化存储
import requests 引用模块
2.1参数
import requests
#1.指定url
url = 'https://www.sogou.com/'
#2.发起请求,get的返回值是一个响应对象
response = requests.get(url)
#3.获取响应数据,text属性返回的是字符串形式的响应数据
page_text = response.text
host_list = response.json()#转换json类型
page_data = response.content #获取二进制响应数据
response.text #获取响应字节
#4,持久化存储
with open('./sogou.html','w',encoding='utf-8') as fp:
fp.write(page_text)
2.2简易的网页采集器
url = 'https://www.sogou.com/web?query=人民币'
response = requests.get(url)
page_text = response.text
with open('./人民币.html','w',encoding='utf-8') as fp:
fp.write(page_text)
2.2.1上述代码出现的问题:
- 出现了乱码
- 数据的量级不够
2.2.2处理乱码
import requests
url = 'https://www.sogou.com/web?query=人民币'
response = requests.get(url)
#修改响应数据的编码格式
response.encoding = 'utf-8'#进行编码转义
page_text = response.text
with open('./人民币.html','w',encoding='utf-8') as fp:
fp.write(page_text)
2.2.3处理数据量级问题
- 遇到了对应的反爬机制
- 反爬机制:UA检测
- 反反爬策略:UA伪装
- UA伪装的实现:
- 1.定义一个字典
- 2.在字典中进行相关请求头信息的伪装
- 3.将该字典作用到get方法的headers参数中即可
- UA检测被作用到了大量的网站中,因此日后,爬虫程序编写中一定要直接加上UA的操作
#伪装请求头
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
response = requests.get(url,headers=headers)#UA伪装
import requests
url = 'https://www.sogou.com/web?query=人民币'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
response = requests.get(url,headers=headers)#UA伪装
#修改响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text#获取响应数据
with open('./人民币.html','w',encoding='utf-8') as fp:
fp.write(page_text)
2.2.4最终实现
使用请求参数的动态化
#参数动态化
wd = input('enter a key word:')
#query是接受输入信息变量通过https://www.sogou.com/web?query="人民币" 传递
param = {
'query':wd#
}
response = requests.get(url,headers=headers,params=param)#UA伪装
实现原理:
- 1.定义一个字典
- 2.字典中的键值就是url携带的参数
- 3.将字典作用到get方法的params参数中
- 代码实现
import requests
url = 'https://www.sogou.com/web'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
#参数动态化
wd = input('enter a key word:')
#query是接受输入信息变量通过https://www.sogou.com/web?query="人民币" 传递
param = {
'query':wd
}
response = requests.get(url,headers=headers,params=param)#UA伪装
#修改响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text
fileName = wd+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(fileName,'爬取成功!!!')
5.动态加载的数据
如何判定是否是动态加载
#产生动态加载的情况
ajax,#能获取到原生的数据
js只能拦截到函数 需要手动获取返回值
- 概念:通过其他/另一个请求请求到的数据
- 特性:可见非可得
- 判定相关的页面数据是否为动态加载的数据?
- 基于抓包工具定位到浏览器地址栏url对应的请求数据包,进行局部搜索:
- 搜索到:这组被搜索的数据不是动态加载的,可以直接爬取
- 没有搜到:这组数据是动态加载的,不可以直接爬取。
- 基于抓包工具定位到浏览器地址栏url对应的请求数据包,进行局部搜索:
- 如何捕获动态加载的数据?
- 基于抓包工具进行全局搜索,最终可以定位到动态加载数据对应的数据包。
- 从数据包可以提取出url和数据
通过使用特定的套路 也就是捕获数据 进行请求的返回加载
xhr查看ajax对应的数据包
局部搜索
全局搜索 点击随便一个包全局搜索 ctrl+f 全局搜索
局部搜索 点击response页面数据进行查询
2.3案例动态数据简单练习
需求:爬取豆瓣电影的详情数据
- 分析:https://movie.douban.com/j/chart/top_list
- 更多的电影数据是通过将滚轮滑动到底部后发起了ajax请求请求到的电影数据
- 对ajax请求的url进行捕获
- 对ajax请求的url进行请求发送
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
url = 'https://movie.douban.com/j/chart/top_list'
fp = open('./movieData.txt','a+',encoding='utf-8')
数据的获取xhr浏览器的开发者工具
for i in range(0,10):
param = {
'type': '13',
'interval_id': '100:90',
'action': '',
'start': str(i*20), #指定开始序号
'limit': '20', # 限制每次获取条数
}
response = requests.get(url=url,params=param,headers=headers)
#json()将json串进行序列化
movie_list = response.json()
for dic in movie_list:
name = dic['title']
score = dic['score']
fp.write(name+':'+score+'\n')
print('第{}页数据爬取成功!'.format(i))
fp.close()
肯德基餐厅查询
-
分析:
- 动态加载数据
-
动态加载数据
- 概念:通过其他/另一个请求请求到的数据(ajax)
- 特性:可以在网页上看见名但是获取不到数据
- 判定相关的页面数据是否为动态加载的数据?
- 基于抓包工具定位到浏览器地址栏url对应的请求数据包,进行局部搜索:
- 搜索到:这组被搜索的数据不是动态加载的,可以直接爬取
- 没有搜到:这组数据是动态加载的,不可以直接爬取。
- 基于抓包工具定位到浏览器地址栏url对应的请求数据包,进行局部搜索:
- 如何捕获动态加载的数据?
- 基于抓包工具进行全局搜索,最终可以定位到动态加载数据对应的数据包。
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
data = {
'cname': '',
'pid': '',
'keyword': '广州',
'pageIndex': '1',
'pageSize': '10',
}
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
response = requests.post(url=url,headers=headers,data=data)
pos_data = response.json()
pos_data
药监总局数据爬取,爬取的是每一家企业的详情数据
- 分析:
- 打开了某一家企业的详情页面,看到了企业的详情数据
- 判定改家企业的详情数据是否为动态加载的?
- 进行局部搜索
- 没有搜索到,说明数据是动态加载出来的
- 捕获动态加载的数据?
- 全局搜索,定位到了动态加载数据对应的数据包,提取出了url和请求参数
- 进行局部搜索
- 成功的捕获到了一家企业对应的详情数据
- 通过上述方式继续分析第二家企业,发现:
- 捕获每一家企业的id
- 在首页中,通过抓包工具对企业名称进行搜索,对应的数据包中发现了企业名称和id
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
#获取企业id
ids = [] #存储所有企业的id
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
for page in range(1,6):
data = {
'on': 'true',
'page': str(page),
'pageSize': '15',
'productName': '',
'conditionType': '1',
'applyname': '',
'applysn': '',
}
company_datas_json = requests.post(url=url,headers=headers,data=data).json()
for dic in company_datas_json['list']:
_id = dic['ID']
ids.append(_id)
detail_url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
for _id in ids:
data = {
'id':_id
}
company_json = requests.post(url=detail_url,headers=headers,data=data).json()
print(company_json['epsName'],company_json['epsProductAddress'])
2.4get请求和post请求的区别
get是param ?参数 get(param=param)
post是data 请求体里面的参数 post(data=data)
url = 'https://www.sogou.com/web'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
#参数动态化
wd = input('enter a key word:')
param = {
'query':wd#查询寻找指定页面
}
response = requests.get(url,headers=headers,params=param)#UA伪装
#修改响应数据的编码格式
response.encoding = 'utf-8'
page_text = response.text
fileName = wd+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(fileName,'爬取成功!!!')
cmd命令
shift+右键点击 进入cmd
urllib 低版本的requests
1.不能进行ua伪装
#ua伪装
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
2.请求头不一样
3.可以直接进行爬去数据的存储
使用方法
import urllib
url = 'http://duanziwang.com/usr/uploads/2019/02/3334500855.jpg'
urllib.request.urlretrieve(url=url,filename='./2.jpg')
#url 指定图片路径地址 filename 图片路径地址
6.浏览器开发者工具
抓包工具中response中显示的页面源码和开发者工具的Element选项卡显示的页面源码的区别是什么?
Elements
等待数据全部加载完毕之后显示的所有数据 (包含动态加载数据)
Response
显示的内容仅仅是当前一个请求请求到的数据(不包含动态加载的数据)

浙公网安备 33010602011771号