[TOC] #### 1. 本文概述 --- 我们在之前的爬虫中其实已经使用过 `headers` 了,文章地址:[Python 爬虫从入门到实战(附豆瓣/电影天堂案例)](https://www.itqaq.com/index/713.html) `header` 为 HTTP 协议中的请求头 一般存放一些和请求内容无关的数据,有时也会存放一些安全验证信息。比如常见的 User-Agent,token,cookie 等信息 通过 requests 发送的请求,我们可以把请求头信息放在 headers 中,也可以单独进行存放,最终由 requests 自动帮我们拼接成完整的 HTTP 请求头 本文内容: + 模拟浏览器登录(处理 cookie) + 防盗链处理(抓取梨视频数据) + 代理(防止被封IP) + 接入第三方代理 #### 2. 处理 cookie(登录小说网) --- 登录小说网,并且获取书架上的书籍列表 ```python ''' 需求:获取小说网书架上的内容 https://www.biquge123.org 1.登录 -> 得到 cookie 2.带着 cookie 去请求 书架url -> 得到书架上的内容 必须把上面两个操作连起来 我们可以使用 session 进行请求 -> session 你可以认为是一连串的请求,在这个过程中 cookie 不会丢失 ''' import requests # 会话 session = requests.session() headers = { 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36' } # 1.登录小说网站 data = { 'action': 'login', 'username': 'xxx', 'password': 'xxxx' } url = 'https://www.biquge123.org/user/action.html' resp = session.post(url, data=data, headers=headers) # print(resp.text) # 响应结果 print(resp.cookies) # 查看 cookie # 2.拿书架上的数据(刚才的那个 session 中是有 cookie 的) import time ms_ts = int(time.time() * 1000) # 接口需要传毫秒时间戳 url2 = 'https://www.biquge123.org/user/action.html?action=bookcase&t=' + str(ms_ts) resp2 = session.get(url2, headers=headers) # print(resp2.text) bookcase = resp2.json() for item in bookcase: print(item) # 书架上的每个书籍信息 ``` 也可以将 `cookie` 直接放在 `header` 中传递 ```python import requests headers = { 'cookie': 'xxx', 'user-agent': 'xxx' } bookcase = requests.get(url='xxxx', headers=headers).json() ``` #### 3. 防盗链处理(抓取梨视频数据) --- 在 Python 爬虫开发中,防盗链是一种非常常见的技术。 它是网站为了保护自身资源(如: 图片/视频)不被其它网站直接盗用、从而节省服务器带宽流量而采取的一种安全机制。 防盗链的核心原理:防盗链机制主要依赖于 HTTP 请求头中的 `Referer` 字段 当用户在浏览器点击链接访问资源时,浏览器会自动在请求头中添加 `Referer` 字段,指明当前请求是从哪个页面发起,服务器通过校验这个字段来判断请求是否合法: + 合法请求:如果 `Referer` 是网站自身的页面地址,服务器会认为这是正常用户的访问,正常返回资源 + 非法请求:如果 `Referer` 为空,或者指向了其它非授权网站,服务器会拒绝提供资源 ```python import requests # 页面地址 # url = "https://www.pearvideo.com/video_1806119" url = 'https://www.pearvideo.com/video_1806083' contId = url.split('_')[1] # 接口地址 api = f'https://www.pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.7941725712112339' headers = { # 1.没有加 headers 的时候提示 “该文章已下线”,尝试加 user-agent 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36', # 2.加 user-agent 后发现仍提示 “该文章已下线”,再加 referer 防盗链(加完发现能拿到数据了) 'referer': url, # 可以发现值就是当前页面地址 } resp = requests.get(api, headers=headers) videoDict = resp.json() print(videoDict) srcUrl = videoDict['videoInfo']['videos']['srcUrl'] newUrl = srcUrl.replace(videoDict['systemTime'], 'cont-' + contId) print(newUrl) # 视频地址 # 下载视频 with open(f'{contId}.mp4', 'wb') as f: f.write(requests.get(newUrl, headers=headers).content) ``` #### 4. 代理(防止封 IP) --- 在 Python 爬虫开发中,`requests` 模块的代理(Proxy)功能是一项核心且高频使用的技术 它的主要作用是隐藏客户端的真实 IP 地址、突破目标网站的 IP 访问频率限制(防封禁),以及提高网站请求的匿名性 ```python # 代理:可以使用第三方的机器来代理你的请求 # 原理:通过第三方的一个机器去发送请求 # 代理的弊端:慢、代理IP不好找(好的代理一般都收费) import requests # 免费代理网站 # 站大爷:https://www.zdaye.com # 快代理:https://www.kuaidaili.com/free/intr proxy = { # http 请求走这个代理 'http': 'http://39.105.27.30:3128', # https 请求走这个代理 'https': 'http://218.77.183.214:5224', } resp = requests.get('https://www.baidu.com', proxies=proxy) resp.encoding = 'utf-8' print(resp.text) ``` #### 5. 接入第三方代理 --- 接入第三方代理的基本用法: ```python import requests # 使用快代理(隧道代理 Pro):https://www.kuaidaili.com # 1.隧道域名:端口号 tunnel = "p632.kdltpspro.com:15818" # 2.用户名密码方式 username = "t18246311xxx" password = "5xw2xxxx" # 3.最终的代理地址 proxies = { "http": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": tunnel}, "https": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": tunnel} } resp = requests.get('https://www.baidu.com', proxies=proxies) resp.encoding = 'utf-8' if resp.status_code == 200: print(resp.text) ``` 第三方代理池IP使用示例: ```python import requests # 代理池IP列表 def get_ip(): # 私密代理-生成API链接(快代理平台-付费购买) url = 'https://dps.kdlapi.com/api/getdps/?secret_id=xxx&signature=xxxx&num=10&format=json&sep=1&dedup=1' resp = requests.get(url) ips = resp.json() proxy_list = ips['data']['proxy_list'] print(f"本次获取代理池总数:{len(proxy_list)}") for proxy in proxy_list: # 拿到每一个 ip yield proxy # 生成器写法 # 爬虫 def spider(): gen = get_ip() url = 'https://www.baidu.com' index = 0 while True: # 代理IP全部耗尽自动终止循环 try: proxy_ip = next(gen) except StopIteration: print("===== 代理池所有IP已全部使用完毕,爬虫终止 =====") break # 使用代理IP发送请求 index += 1 proxies = {'http': 'http://' + proxy_ip, 'https': 'http://' + proxy_ip } try: resp = requests.get(url, proxies=proxies) resp.encoding = 'utf-8' print(f'恭喜您,第{index}个IP: {proxy_ip} 请求成功 !') return resp.text except Exception as e: print(f'第{index}个IP: {proxy_ip} 请求失败,换下一个 | 错误:{str(e)[:80]}') if __name__ == '__main__': result = spider() if result: print("爬虫成功返回数据:") print(result) else: print("全部代理IP均失效,爬虫未获取到内容") # 获取所有 ip,但是这个地方一般不会这么写 # for proxy in gen: # print(proxy) # 推荐写法:一个一个去拿 IP # print(next(gen)) # print(next(gen)) # print(next(gen)) ```