Python爬虫开发:requests库高级用法与实战案例
1. 项目概述今天咱们来聊聊Python爬虫开发中requests库的那些高级用法。作为一名爬虫工程师requests库可以说是日常开发中最常用的工具之一。但很多朋友可能只停留在简单的get/post请求层面其实requests还有很多强大的功能值得挖掘。这篇文章将重点介绍requests库的几个高级应用场景JSON解析、SSL认证、代理设置、超时控制、异常处理以及文件上传。同时还会分享如何搭建代理池、Django获取客户端IP以及两个实战案例——视频网站和新闻网站的爬取。2. requests高级用法详解2.1 JSON数据解析在爬虫开发中我们经常需要处理API返回的JSON数据。requests提供了非常便捷的JSON解析方法import requests data { keyword: 北京, pageIndex: 1, pageSize: 10 } response requests.post(http://example.com/api/stores, datadata) # 方法1手动解析JSON字符串 import json result json.loads(response.text) # 方法2直接使用response.json() result response.json() # 直接返回字典对象 print(result[data][0][storeName])注意使用response.json()时如果响应内容不是合法的JSON格式会抛出json.decoder.JSONDecodeError异常。2.2 SSL证书验证当访问HTTPS网站时可能会遇到SSL证书验证问题# 忽略SSL证书验证不推荐生产环境使用 response requests.get(https://example.com, verifyFalse) # 关闭SSL警告 import urllib3 urllib3.disable_warnings() # 指定自定义证书路径适合企业级应用 response requests.get(https://example.com, cert(/path/to/cert.pem, /path/to/key.pem))SSL证书验证是保证通信安全的重要机制在测试环境可以临时关闭验证但在生产环境应该配置正确的证书。2.3 代理设置代理是爬虫开发中绕不开的话题requests设置代理非常简单proxies { http: http://proxy.example.com:8080, https: http://secureproxy.example.com:8090 } response requests.get(http://target.com, proxiesproxies)代理类型主要分为透明代理服务端可以获取真实客户端IP匿名代理服务端知道使用了代理但不知道真实IP高匿代理服务端无法检测到代理使用2.4 超时设置合理的超时设置可以避免程序长时间挂起# 连接超时和读取超时都设为3秒 response requests.get(http://example.com, timeout3) # 分别设置连接超时和读取超时 response requests.get(http://example.com, timeout(2, 5)) # 连接2秒读取5秒2.5 异常处理完善的异常处理能让爬虫更健壮from requests.exceptions import RequestException, Timeout try: response requests.get(http://example.com, timeout1) response.raise_for_status() # 检查HTTP状态码 except Timeout: print(请求超时) except RequestException as e: print(f请求出错: {e})2.6 文件上传使用requests上传文件也很简单files {file: open(example.pdf, rb)} response requests.post(http://upload.example.com, filesfiles)3. 代理池搭建实战3.1 代理池架构一个完整的代理池通常包含以下组件爬取模块从免费代理网站抓取代理IP存储模块使用Redis存储代理IP检测模块定期验证代理可用性API模块提供获取代理的接口3.2 使用开源代理池推荐使用jhao104/proxy_pool这个开源项目# 克隆项目 git clone https://github.com/jhao104/proxy_pool.git # 安装依赖 pip install -r requirements.txt # 配置Redis连接 # 修改setting.py中的DB_CONN # 启动调度程序 python proxyPool.py schedule # 启动API服务 python proxyPool.py server3.3 代理池使用示例import requests # 获取随机代理 proxy requests.get(http://localhost:5010/get/).json() proxies { http: fhttp://{proxy[proxy]}, https: fhttp://{proxy[proxy]} } # 使用代理发送请求 try: response requests.get(http://target.com, proxiesproxies, timeout5) print(response.text) except Exception as e: print(f请求失败: {e}) # 将失效代理删除 requests.get(fhttp://localhost:5010/delete/?proxy{proxy[proxy]})4. Django获取客户端IP在Django中获取客户端真实IP需要考虑多种情况# settings.py ALLOWED_HOSTS [*] # views.py from django.http import HttpResponse def get_client_ip(request): x_forwarded_for request.META.get(HTTP_X_FORWARDED_FOR) if x_forwarded_for: ip x_forwarded_for.split(,)[0] # 获取第一个IP else: ip request.META.get(REMOTE_ADDR) return HttpResponse(ip)常见HTTP头中的IP相关信息REMOTE_ADDR直接客户端IPHTTP_X_FORWARDED_FOR经过代理时的IP链HTTP_CLIENT_IP客户端IP不太可靠5. 实战案例视频网站爬取以某视频网站为例展示如何爬取视频资源import requests import re # 1. 获取视频列表页 list_url https://www.pearvideo.com/category_1 response requests.get(list_url) video_ids re.findall(rvideo_(\d), response.text) # 2. 获取每个视频的真实地址 for vid in video_ids: # 伪造Referer headers { Referer: fhttps://www.pearvideo.com/video_{vid} } # 获取视频信息 info_url fhttps://www.pearvideo.com/videoStatus.jsp?contId{vid} info requests.get(info_url, headersheaders).json() # 解析真实视频地址 fake_url info[videoInfo][videos][srcUrl] real_url fake_url.replace(fake_url.split(/)[-1].split(-)[0], fcont-{vid}) # 下载视频 video_data requests.get(real_url, streamTrue) with open(f{vid}.mp4, wb) as f: for chunk in video_data.iter_content(1024): f.write(chunk)关键点注意反爬机制需要设置Referer视频地址需要二次处理才能得到真实地址大文件下载使用stream模式6. 实战案例新闻网站爬取使用BeautifulSoup解析新闻页面import requests from bs4 import BeautifulSoup url https://news.example.com response requests.get(url) soup BeautifulSoup(response.text, lxml) news_list [] for item in soup.select(.news-item): title item.select_one(.title).text.strip() link item.select_one(a)[href] time item.select_one(.time).text # 处理相对链接 if not link.startswith(http): link url link news_list.append({ title: title, link: link, time: time }) # 存储到数据库 import pymysql conn pymysql.connect(hostlocalhost, userroot, password123456, dbnews) try: with conn.cursor() as cursor: sql INSERT INTO news (title, link, publish_time) VALUES (%s, %s, %s) for news in news_list: cursor.execute(sql, (news[title], news[link], news[time])) conn.commit() finally: conn.close()7. 常见问题与解决方案7.1 请求频率过高被限制解决方案使用代理池轮换IP添加随机延迟设置合理的请求头User-Agent等import time import random time.sleep(random.uniform(0.5, 1.5)) # 随机延迟7.2 验证码识别应对方案使用第三方验证码识别服务人工打码尝试绕过验证码修改Cookie等7.3 数据动态加载处理方法分析Ajax请求接口使用Selenium等浏览器自动化工具解析JavaScript代码7.4 数据存储优化建议使用批量插入提高数据库写入效率考虑使用消息队列解耦爬取和存储定期清理无效数据8. 爬虫开发最佳实践遵守robots.txt检查目标网站的爬虫协议设置合理的请求间隔避免给服务器造成过大压力错误重试机制对临时性错误进行自动重试日志记录详细记录爬取过程方便排查问题数据去重使用BloomFilter等高效去重算法# 重试装饰器示例 import time from functools import wraps def retry(max_retries3, delay1): def decorator(func): wraps(func) def wrapper(*args, **kwargs): retries 0 while retries max_retries: try: return func(*args, **kwargs) except Exception as e: retries 1 if retries max_retries: raise time.sleep(delay) return wrapper return decorator retry(max_retries5, delay2) def fetch_url(url): response requests.get(url, timeout5) response.raise_for_status() return response.text9. 性能优化技巧连接复用使用Session对象复用TCP连接异步请求配合aiohttp实现异步爬取分布式爬取使用Scrapy-Redis等框架缓存机制对不变的数据进行缓存# 使用Session提高性能 session requests.Session() # 第一次请求会建立TCP连接 response session.get(http://example.com) # 后续请求复用已有连接 response2 session.get(http://example.com/page2)10. 法律与道德考量尊重版权不要爬取受版权保护的内容隐私保护不要收集和存储个人隐私信息服务条款遵守目标网站的使用条款数据安全妥善保管爬取的数据爬虫开发不仅是个技术活还需要考虑法律和道德层面的问题。在开始爬取前务必确认你的行为是合法合规的。