爬虫基本原理
爬虫原理 — 本质就是可见皆可爬
1 确认目标url
如何抓包?
- 获取数据之前需要做生成数据包的操作,即清空数据包,点击生成(例如点击翻译按钮、点击评论信息所在的评论按钮)
- 寻找数据包,查看preview预览图或者response响应数据是否有你想要的数据(ctrl+f可以进行搜索)
url的定义
url:统一资源定位符,如一个网页、一张图片、一个视频等都可以用一个url唯一来确定
url的组成
协议:// [用户名和密码] 主机地址(域名或ip地址) [端口号] [路径] [查询参数] [片段]
-
协议
:http、https、ftp等,但爬虫抓取的页面是基于http和https协议的 -
HTTP
:超文本传输协议,表示超出文本的数据可以从网页传输到浏览器;而HTTPS是以安全为目的的HTTP通道,在HTTP的基础上加了个SSL,协议传输的内容会通过SSL进行加密,保证数据的传输的安全性 -
用户名和密码
:有些url需要带上用户名和密码才可以访问 -
主机地址
:包括域名和ip地址,如https://www.baidu.com中的www.baidu.com就是域名,而https://8.8.8.8中的8.8.8.8就是ip地址 -
端口
:服务器设定的服务端口,如https://192.168.0.0.1:8080中的8080就是端口。有些url没有端口信息,是使用了默认的端口, http协议的默认端口是80,https协议的默认端口是443,所以http://www.baidu.com相当于http://www.baidu.com:80,而https://www.baidu.com相当于https://www.baidu.com:443 -
路径
:网络资源在服务器中的指定地址,如https://github.com/favicon.ico中的路径就是favicon.ico,表示访问github根目录下的favicon.ico -
查询参数
:用来查询某类资源,如果有多个查询,使用&隔开。例如https://www.baidu.com/s?wd=查询内容&ie=utf-8,wd=查询内容&ie=utf-8就是查询参数
2. 发送请求
模拟浏览器向目标url发送请求(requests第三方库),要确定好请求方式,可以在Request Method中查看
http请求过程(浏览器原理)
在浏览器中的地址栏输入一个url,可以看到网页的返回。实际上,这是浏览器向网站所在的服务器发送了一个请求,网站服务器接收到请求后对其进行处理和解析,然后将对应的响应传给浏览器,浏览器再对其进行解析,将网页呈现出来。
- 在浏览器地址栏中输入url
- url会被发送给DNS服务器
- DNS服务器会根据url域名解析出对应的ip地址
- 通过ip地址定位到某台服务器
- 服务器会返回给我们数据(html文字样式+css渲染工具+js行为+jpg图片),组成了我们看到的网页
- 所以,查找百度的ip地址,ping www.baidu.com后,也可以直接在地址栏输入百度的ip地址进行访问
通过打开谷歌开发者工具的network监听组件,刷新网页后network面板有很多个条目,一个条目就代表一次发送请求和接收响应的过程。
请求方法
-
get请求
-
请求参数可以在url中看到,参数会显示在地址栏中,不太安全
-
提交的数据最多只能有1024字节
-
post请求
-
通过data参数携带表单数据提交,安全性相对较高;(登陆操作通常是post请求,因为登录时需要提交密码这类敏感信息,如果使用get方法会将密码暴露在url中,造成密码泄露)
-
提交的数据没有限制(上传文件时,由于文件的内容比较大,可以使用post请求)
请求头
服务器会根据请求头里的信息判断请求是否合法,进而做出对应的响应
-
user_agent
: 发出请求的用户信息,浏览器型号、版本、操作系统信息 -
referer
:请求是从哪个页面跳转过来的 -
cookie
: 标识了我们所对应的服务器的会话,我们输入用户名和密码成功登录某个网站后,服务器会用会话保存登录状态信息,之后每次请求这个网站的页面时,都会在请求头加上cookie并将其发送给服务器,服务器通过cookie识别出是我们自己,并查出当前状态是登录状态,所以返回的结果是登录后才能看到的网页内容 (维持当前访问会话)
请求体
- 请求体一般承载的内容是
post
请求的表单数据,对于get请求,请求体为空。 -
content-type
与post
提交数据方式的关系:使用post请求需要使用正确的content-type,否则会导致post请求提交后无法得到正确对的响应 - 提交表单数据登录后
request headers
中指定content-type
为application/x-www-form-rulencoded
,这样设置后内容才会以表单数据的形式提交- 如果设置为
application/json
,则是提交json数据 - 如果设置为
multipart/form-data
,则是将表单文件上传
请求参数
- params参数
如果url携带的参数太多,可以使用params参数来传递。添加params参数后,会以?a=1
的形式加在请求路径后面
import requests url = "http://www.baidu.com/s"
payload = { "wd": "爬虫" }
response = requests.get(url, params=payload)
print(response.url)
# https://www.baidu.com/s?wd=爬虫
3. 获取响应
服务端把响应数据给到客户端 (response)
响应头
响应头是响应的一部分,包含服务器的类型、文档类型、日期等信息,浏览器在接收到响应后,会对其进行解析,进而呈现出网页内容。
-
date
:响应产生的时间 -
last-modified
:指定资源最后修改的时间 -
content-encoding
:指定响应内容的编码 -
server
:服务器的信息 -
content-type
:文档类型,指定返回的数据是什么类型,例如:text/html返回的是html文档,application/x-javascript返回的是javascript文件,image/jpeg返回的是图片 -
set-cookie
:设置cookie,用于告诉浏览器需要将此内容放在cookie中,下次请求时将cookie带上
响应状态码
服务器的响应状态,response.status_code,检查是否请求成功,如果是200可以做数据做进一步处理。
-
1**
: 信息,服务器收到请求、需要请求者继续执行操作 -
2**
: 成功,操作被成功接收并处理 (200–请求成功) -
3**
: 重定向,需要进一步的操作以完成请求 (301–资源被永久跳转到其url) -
4**
: 客户端错误 (404–请求资源不存在) -
5**
: 服务器错误 (500–服务器内部发生错误)
响应体
响应的正文数据存储在响应体中
- 请求网页时,响应体就是网页的
html代码
- 请求一张图片时,响应体就是图片的
二进制数据
# response.text -- 字符串数据
with open("文章.txt", "w", encoding="utf-8") as f:
f.write(response.text)
# response.content.decode() -- 字符串数据
with open("文章.txt", "w", encoding="utf-8") as f:
f.write(response.content.decode())
# response.content -- 二进制数据
with open("周杰伦.jpg", "wb")as f:
f.write(response.content)
响应文本与编码
-
response.text
:返回的是字符串数据(本身是字节类型,但会以一种猜测的编码格式自动帮你解码成字符串) -
response.content
:返回的是二进制数据,需要使用.decode()进行解码,转成字符串类型 -
response.encoding
:http头猜测的网页编码格式
网页编码格式错误如何解决?
print(response.text) # 得到的文本可能是乱码
print(response.encoding)
# 因为requests猜测的网页编码格式出现错误,导致出现乱码。 ISO-8859-l,实际上是utf-8
方法一:手动指定一下编码格式
response.encoding = "utf-8"
print(response.text) # 指定后再次打印就不会出现乱码
方法二:使用“字符串文件编码检测模块”chardet,将chardet探测到的编码赋值给response.encoding解码
print(chardet.detect(response.content))
# 字典 {'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
response.encoding = chardet.detect(response.content)["encoding"]
print(response.text)
方法三 :.decode()解码
print(response.content.decode())
4. 解析数据
确认响应数据response的数据类型,对响应数据进行解析,提取特定的数据。
- 如果是
html类型
,可以使用Xpath、正则、BeautifulSoup(CSS选择器)提取 - 如果是
json类型
,可以使用内置模块json、第三方库jsonpath、正则提取。
import json
response_data = '{"name": "John", "age": 30, "city": "New York"}' # 这里假设响应数据是一个JSON字符串
# 解析JSON数据
data = json.loads(response_data)
# 提取数据
name = data['name']
age = data['age']
city = data['city']
print(name, age, city) # 输出: John 30 New York
动态网页
的抓取主要涉及Ajax和动态Html,简单的网页访问是无法获取完整的数据的,需要对数据加载流程进行分析。
Ajax
全称是Asynchronous JavaScript and XML
,也就是异步的JavaScript
和XML
,是JavaScript
异步加载技术、XML
、Dom
、xhtml
和css
等技术的组合。使用Ajax技术不必刷新整个页面,只需对页面的局部进行更新,Ajax只取回一些必需的数据,它使用SOAP、XML或者支持JSON的Web Service接口,我们在客户端利用JavaScript处理来自服务器的响应,这样客户端和服务器之间的数据交互就减少了,访问速度和用户体验都得到了提升。
如何判断要爬取的网站是动态网站还是静态网站呢?
- 当你使用Requests访问一个网页,返回的Response内容和在浏览器上看的HTML内容不一样时,就是用了动态技术,这就是为什么你无法从响应中抽取出有效的数据。
如果是动态网页如何爬取?
- 使用自动化测试工具(Selenium、Playwright)模拟浏览器的行为
- 或者检查网页的网络请求,找到动态加载数据的API请求
5. 保存数据
-
本地
:txt、csv、json、excel -
数据库(关系型与非关系型)
:redis、mongodb、mysql
想了解更多MySQL知识:http://t.csdn.cn/xrAiz