爬虫的基本流程
-
基本流程
-
目标数据:需要什么数据
-
来源地址
-
结构分析
-
具体数据在哪(网站、还是APP)
-
如何展示的数据
-
-
实现构思
-
编写代码
-
爬虫的基本手段
-
破解请求限制
-
请求头设置,如:useragant为有效客户端
-
控制请求频率(根据实际情景)
-
IP代理
-
签名/加密参数从html/cookie/js分析
-
-
破解登录授权
-
请求带上用户cookie信息
-
-
破解验证码
-
简单的验证码可以使用识图读验证码第三方库
-
解析数据
-
HTML Dom解析
-
正则匹配,通过的正则表达式来匹配想要爬取的数据,如:有些数据不是在html 标签里,而是在html的script 标签的js变量中
-
使用第三方库解析html dom,比较喜欢类jquery的库
-
-
数据字符串
-
正则匹配(根据情景使用)
-
转 JSON/XML 对象进行解析
-
简单爬取页面数据
from urllib.request import urlopen
url = 'http://www.baidu.com'
resp = urlopen(url)
print(resp.read().decode()[:100])
urllib
-
requset.urlopen(url,data,timeout)
-
第一个参数url即为URL,是必须要传送的。第二个参数data是访问URL时要传送的数据,第三个timeout是设置超时时间。
-
第二三个参数是可以不传送的,data默认为空None,timeout默认为`socket._GLOBAL_DEFAULT_TIMEOUT
-
-
response.read()
-
read()方法就是读取文件里的全部内容,返回bytes类型
-
-
response.getcode()
-
返回 HTTP的响应码,成功返回200,4服务器页面出错,5服务器问题
-
-
response.geturl()
-
返回 返回实际数据的实际URL,防止重定向问题
-
-
response.info()
-
返回 服务器响应的HTTP报头
-
获取响应信息
代码 | 含义 |
---|---|
resp.json() | 获取响应内容(以json字符串) |
resp.text | 获取响应内容 (以字符串) |
resp.content | 获取响应内容(以字节的方式) |
resp.encoding | 获取网页编码 |
resp.headers | 获取响应头内容 |
resp.request.headers | 请求头内容 |
resp.url | 获取访问地址 |
resp.cookie | 获取cookie |
request对象
使用urllib.request.urlopen发送请求时,可以将参数封装到一个Request对象中。
参数包含:
-
url 发送的请求链接
-
headers 请求头信息
-
data 请求数据
请求头
名称 | 含义 |
---|---|
Accept | 告诉服务器,客户端支持的数据类型 |
Accept-Charset | 告诉服务器,客户端采用的编码 |
Accept-Encoding | 告诉服务器,客户机支持的数据压缩格式 |
Accept-Language | 告诉服务器,客户机的语言环境 |
Host | 客户机通过这个头告诉服务器,想访问的主机名 |
If-Modified-Since | 客户机通过这个头告诉服务器,资源的缓存时间 |
Referer | 客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的。(一般用于防盗链) |
User-Agent | 客户机通过这个头告诉服务器,客户机的软件环境 |
Cookie | 客户机通过这个头告诉服务器,可以向服务器带数据 |
Refresh | 服务器通过这个头,告诉浏览器隔多长时间刷新一次 |
Content-Type | 服务器通过这个头,回送数据的类型 |
Content-Language | 服务器通过这个头,告诉服务器的语言环境 |
Server | 服务器通过这个头,告诉浏览器服务器的类型 |
Content-Encoding | 服务器通过这个头,告诉浏览器数据采用的压缩格式 |
Content-Length | 服务器通过这个头,告诉浏览器回送数据的长度 |
基本请求
HTTP的基本请求
-
get
-
post
-
put
-
delete
-
head
-
options
GET请求
大部分被传输到浏览器的html,images,js,css, … 都是通过GET方法发出请求的。它是获取数据的主要方法
Get请求的参数都是在Url中体现的,如果有中文,需要转码,这时我们可使用
-
urllib.parse.urlencode() 转换键值对
-
urllib.parse. quote() 转换一个值
POST请求
POST请求的参数需要放到Request请求对象中,data是一个字典,里面要匹配键值对
# 当data为字典,要转换为bytes类型
from urllib.parse import urlencode
_data = {}
data = urlencode(_data).encode
post发送表单数据和json数据皆可
import requests
url = url
# from表单数据
from_data = {
"name": "micdy",
"book": "test"
}
req = requests.post(url, data=from_data)
print(req.text)
# json数据
json_data = {
"name": "micdy",
"book": "test"
}
req = requests.post(url, json=json_data)
print(req.text)
Cookie
urlib使用cookie
使用cookie保持登录,为了保持Cookie不丢失可以urllib.request.HTTPCookieProcessor
来扩展opener的功能
handler = HTTPCookieProcessor()
opener = build_opener(handler)
保存cookie
可以利用本模块的http.cookiejar.CookieJar
类的对象来捕获cookie并在后续连接请求时重新发送,比如可以实现模拟登录功能。该模块主要的对象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar
cookie_jar = MozillaCookieJar()
handler = HTTPCookieProcessor(cookie_jar)
cookie_jar.save('cookie.txt',ignore_discard=True,ignore_expires=True)
使用保存的cookie
cookie_jar.load('cookie.txt',ignore_discard=True,ignore_expires=True)
handler = HTTPCookieProcessor(cookie_jar)
opener = build_opener(handler)
requests使用cookie
使用Session方法启用会话
s = requests.Session()
print(s.cookies)
'''
-> Cookie session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTczNzYxOTMxNn0.EbyLG-885Ng3sAIr7NNxZS0NnufKSe6jm76rzVAa7r8
'''
requests.Session()
会创建一个会话对象,这个对象会在多次请求间自动管理 cookie
。当你使用这个会话对象发送请求时,服务器返回的 Set - Cookie
头信息会被会话对象自动保存。在后续使用该会话对象发送的请求中,会话对象会自动在请求头里添加保存的 cookie
,从而保持会话状态。
-
创建会话对象:
s = requests.Session()
创建了一个Session
对象s
。 -
登录请求:
login_resp = s.post(url, data=form_data)
发送登录请求,服务器返回的cookie
会被s
自动保存。 -
后续请求:
info_resp = s.get(url)
发送后续请求时,s
会自动在请求头中添加之前保存的cookie
,以此保持会话状态。
import requests
def login():
url = "http://localhost:8000/playground/login"
data = {
"uname": "admin",
"password": "123456"
}
s = requests.Session()
login_resp = s.post(url, data=data)
url = "http://localhost:8000/playground/user_info"
login_resp = s.get(url)
print(login_resp.text)
if __name__ == "__main__":
login()
Token
Token是服务器生成的一串字符串,作为客户端在后续请求时的身份标识和授权依据。客户端成功登录或完成特定操作后,服务器会创建一个Token并返回给客户端,之后客户端每次向服务器发送请求时都需要携带这个Token,服务器通过验证Token的有效性来确认客户端的身份和权限。
服务器接收到登录信息后,对用户的身份进行验证,若验证通过,服务器会根据用户的相关信息(如用户 ID、角色等)生成一个Token。
Token具有时效性。
Token通常由三部分组成
-
头部(Header):包含Token的类型(如JWT)和使用的签名算法(如 HMAC SHA256、RSA 等),并进行Base64Url编码。
-
载荷(payload):包含声明(Claims),声明是关于实体(通常是用户)和其他数据的声明,可分为注册声明(如iss发行人、sub主题、aud受众等)、公开声明和私有声明。同样进行 Base64Url 编码。
-
签名(Signature):为了创建签名部分,需要使用编码后的头部、编码后的载荷、一个秘钥(只有服务器知道),使用头部中指定的签名算法进行签名,以确保Token未被篡改。
服务器将生成的Token返回给客户端,客户端通常会将Token存储在本地,如浏览器的本地存储(Local Storage)或会话存储(Session Storage)中,也可以存储在Cookie里。
后续的请求中,可以在Authorization
字段携带Token,服务器会对Token进行验证,
利用Token登录
import requests
url = "http://localhost:8000/playground/login2"
data = {
"uname": "admin",
"password": "123456"
}
resp = requests.post(url, json=data)
token = resp.json().get("access_token")
login_url = "http://localhost:8000/playground/user_info2"
headers = {
"Authorization": f"Bearer {token}"
}
resp = requests.get(login_url, headers=headers)
print(resp.json())
使用场景
-
身份验证:用于验证用户的身份,确保只有经过授权的用户才能访问受保护的资源。例如,用户登录电商网站后,服务器生成 Token,用户在浏览个人订单、修改个人信息等操作时都需要携带该 Token 进行身份验证。
-
授权:可以根据 Token 中包含的用户角色和权限信息,决定用户可以执行哪些操作。比如,管理员用户的 Token 可能包含更高的权限,允许其进行用户管理、商品上架等操作,而普通用户的 Token 权限则相对较低。
-
单点登录(SSO):在多个相关的 Web 应用中,用户只需在一个应用中登录,服务器生成的 Token 可以在其他关联应用中使用,实现一次登录,多处访问。
urllib底层
当你获取一个URL你使用一个opener(一个urllib.OpenerDirector的实例)。在前面,我们都是使用的默认的opener,也就是urlopen。它是一个特殊的opener,可以理解成opener的一个特殊实例,传入的参数仅仅是url,data,timeout
如果我们需要用到Cookie,只用这个opener是不能达到目的的,所以我们需要创建更一般的opener来实现对Cookie的设置
网页页面
-
静态页面:访问有UI页面URL,可以直接获取数据
-
动态页面(AJAX):访问有UI页面URL,不能获取数据。需要抓取新的请求获取数据
有些网页内容使用AJAX加载,而AJAX一般返回的是JSON,直接对AJAX地址进行post或get,就能返回JSON数据了。在xhr,异步请求中寻找。
SSL证书
如果SSL证书验证不通过,或者操作系统不信任服务器的安全证书,会警告用户证书不受信任。
忽略ssl的安全性
import ssl
context = ssl._creat_unverified_context()
response = urlopen(request,context = context)
伪装爬虫请求
有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应。
fake-useragent
pip install fake-useragent
fake-useragent
在创建对象时,可能创建不了,多部分原因为服务器访问不到的原因
可以拷贝fake-useragent_version.json的配置文件到用户目录
from fake_useragent import UserAgent
ua = UserAgent()
print(ua.chrome)
print(ua.firefox)
print(ua.edge)
Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0
代理ip
代理分类
-
透明代理:目标网站知道你使用了代理并且知道你的源IP地址,这种代理显然不符合我们这里使用代理的初衷
-
匿名代理:匿名程度比较低,也就是网站知道你使用了代理,但是并不知道你的源IP地址
-
高匿代理:这是最保险的方式,目标网站既不知道你使用的代理更不知道你的源IP
代理网站
代理网站目前可用,但不一定稳定。毕竟这个产业目前情况就是这样。
-
66ip 代理 http://www.66ip.cn
构建hander实现
hander = ProxyHandler({'http': 'ip:port'})
opener = build_opener(hander)
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)