Python常见面试题的详解19
1. 如何使用Django 中间件
Django 中间件宛如一个灵活且强大的插件系统,它为开发者提供了在请求处理流程的不同关键节点插入自定义代码的能力。这些节点包括请求抵达视图之前、视图完成处理之后以及响应即将返回给客户端之前。借助中间件,我们可以实现诸如请求预处理、响应后处理、日志记录、权限验证等一系列实用功能,从而增强 Django 应用的可扩展性和灵活性。
- 自定义中间件
python
# myapp/middleware.py
class CustomMiddleware:
def __init__(self, get_response):
"""
初始化中间件,接收一个 get_response 函数,该函数用于调用后续的中间件或视图。
"""
self.get_response = get_response
def __call__(self, request):
"""
中间件的核心调用方法,在请求和响应处理过程中被调用。
"""
# 请求处理前的代码
print("在请求到达视图之前,执行此段代码,可用于请求预处理,如记录请求信息等。")
# 调用后续的中间件或视图,获取响应
response = self.get_response(request)
# 响应处理后的代码
print("在响应返回给客户端之前,执行此段代码,可用于响应后处理,如添加响应头信息等。")
return response
-
中间件配置指南
要让自定义中间件生效,需要在 settings.py
文件中进行配置。在 MIDDLEWARE
列表中添加自定义中间件的路径,确保 Django 能够识别并调用它。
python
MIDDLEWARE = [
# 其他中间件...
'myapp.middleware.CustomMiddleware',
]
-
基于类的中间件方法详解
除了 __call__
方法,基于类的中间件还可以定义其他特定的方法,以满足不同的处理需求。
python
class AnotherMiddleware:
def __init__(self, get_response):
"""
初始化中间件,接收 get_response 函数。
"""
self.get_response = get_response
def __call__(self, request):
"""
处理请求和响应的主要方法。
"""
response = self.get_response(request)
return response
def process_view(self, request, view_func, view_args, view_kwargs):
"""
在视图函数调用之前执行,可用于权限验证、参数预处理等操作。
"""
print("在视图函数调用之前执行此方法,可进行一些前置检查。")
def process_exception(self, request, exception):
"""
当视图函数抛出异常时执行,可用于异常处理和日志记录。
"""
print(f"视图函数抛出异常: {exception},可在此处记录异常信息。")
def process_template_response(self, request, response):
"""
当视图函数返回一个 TemplateResponse 对象时执行,可用于模板响应的后处理。
"""
print("处理模板响应,可对模板响应进行修改或添加额外信息。")
return response
2. Django 中哪里用到了线程,协程和进程
- 线程
1. 开发服务器:Django 的开发服务器(python manage.py runserver
)默认是单线程的,但可以通过 --nothreading
和 --threaded
选项来控制。使用 --threaded
选项时,开发服务器会以多线程方式运行,这样可以同时处理多个请求。
bash
python manage.py runserver --threaded
2. 异步任务处理:在一些需要异步执行的任务中,可以使用线程。例如,在视图中启动一个新线程来处理耗时的操作,避免阻塞主线程。
python
import threading
from django.http import HttpResponse
def long_running_task():
# 模拟耗时操作
import time
time.sleep(5)
def my_view(request):
thread = threading.Thread(target=long_running_task)
thread.start()
return HttpResponse("任务已在后台执行")
- 协程
Django Channels:Django Channels 是一个用于处理异步 Web 协议(如 WebSocket)的库,它基于协程实现。通过 Channels,可以在 Django 中编写异步视图和消费者,处理高并发的连接。
python
# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class MyConsumer(AsyncWebsocketConsumer):
async def connect(self):
await self.accept()
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
await self.send(text_data=json.dumps({
'message': message
}))
- 进程
生产环境部署:在生产环境中,通常会使用 WSGI 服务器(如 Gunicorn、uWSGI)来部署 Django 应用。这些服务器会以多进程的方式运行,每个进程可以处理多个请求,从而提高应用的并发处理能力。
bash
# 使用 Gunicorn 启动 Django 应用
gunicorn myproject.wsgi:application -w 4 # -w 4 表示使用 4 个工作进程
3. Python 网络爬虫用到哪些常用库
requests
库
requests
是 Python 中一个广受欢迎且功能强大的 HTTP 请求库,由 Kenneth Reitz 开发。它以简洁、优雅的 API 设计著称,极大地简化了 HTTP 请求的过程,让开发者可以用最少的代码完成复杂的网络请求操作。无论是发送 GET、POST 请求,还是处理请求头、Cookies、文件上传等,requests
都能轻松应对,是 Python 网络开发中的首选库之一。
- 要点
-
简洁易用:API 设计直观,降低了 HTTP 请求的复杂度,新手也能快速上手。
-
功能全面:支持各种 HTTP 方法,如 GET、POST、PUT、DELETE 等,还能处理请求头、Cookies、文件上传等。
-
自动处理编码:能自动处理响应内容的编码,确保中文等非 ASCII 字符正确显示。
-
会话管理:提供会话对象(
Session
),方便在多个请求之间保持状态,如保持登录状态。
python
import requests
# 发送简单的 GET 请求
response = requests.get('https://www.example.com')
print(response.text)
# 发送带有参数的 GET 请求
params = {'key1': 'value1', 'key2': 'value2'}
response = requests.get('https://www.example.com', params=params)
print(response.url)
# 发送 POST 请求
data = {'username': 'user', 'password': 'pass'}
response = requests.post('https://www.example.com/login', data=data)
print(response.status_code)
# 处理请求头
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get('https://www.example.com', headers=headers)
# 使用会话对象保持状态
session = requests.Session()
session.post('https://www.example.com/login', data=data)
response = session.get('https://www.example.com/dashboard')
print(response.text)
requests
还支持处理超时、SSL 验证、代理等,如下设置超时时间:
python
try:
response = requests.get('https://www.example.com', timeout=5)
except requests.Timeout:
print("请求超时")
aiohttp
库
aiohttp
是基于 Python 的异步 I/O 库 asyncio
构建的 HTTP 客户端 / 服务器库。它充分利用了 Python 的异步特性,能够在单线程中高效地处理大量并发请求,大大提高了网络请求的性能。aiohttp
不仅可以作为客户端发送 HTTP 请求,还可以作为服务器搭建简单的 Web 服务。
- 要点
-
异步性能:基于异步 I/O,避免了传统同步请求中的阻塞问题,适合处理高并发场景。
-
客户端与服务器一体:既可以作为 HTTP 客户端发送请求,也可以作为服务器接收请求。
-
WebSocket 支持:支持 WebSocket 协议,方便开发实时通信应用。
python
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'https://www.example.com')
print(html)
asyncio.run(main())
作为服务器使用
python
from aiohttp import web
async def handle(request):
return web.Response(text="Hello, World!")
app = web.Application()
app.router.add_get('/', handle)
web.run_app(app)
urllib
库
urllib
是 Python 标准库中用于处理 URL 的模块集合。在 Python 3 中,urllib
被重新组织为一个包,包含 urllib.request
、urllib.parse
、urllib.error
等子模块。它提供了从 URL 打开和读取数据、处理 URL 参数、处理异常等基本功能,是 Python 中进行简单网络请求的基础工具。
- 要点
-
标准库支持:无需额外安装,使用方便,适合初学者进行简单的网络请求操作。
-
多模块协作:不同子模块分工明确,分别处理不同的网络请求相关任务。
-
基础功能齐全:涵盖了 URL 解析、请求发送、响应处理等基本操作。
python
import urllib.request
# 发送简单的 GET 请求
with urllib.request.urlopen('https://www.example.com') as response:
html = response.read().decode('utf-8')
print(html)
# 发送带有参数的 GET 请求
import urllib.parse
params = urllib.parse.urlencode({'key1': 'value1', 'key2': 'value2'})
url_with_params = f'https://www.example.com?{params}'
with urllib.request.urlopen(url_with_params) as response:
html = response.read().decode('utf-8')
print(html)
urllib
也可以处理 POST 请求:
python
import urllib.request
import urllib.parse
url = 'https://www.example.com'
data = urllib.parse.urlencode({'key': 'value'}).encode('utf-8')
req = urllib.request.Request(url, data=data, method='POST')
with urllib.request.urlopen(req) as response:
html = response.read().decode('utf-8')
print(html)
urllib2
(Python 2 特有)
在 Python 2 中,urllib2
是一个强大的 HTTP 请求库。它提供了更高级的功能,如自定义请求头、处理 cookies、处理重定向等。与 urllib
不同,urllib2
专注于 HTTP 请求的处理,而 urllib
更侧重于 URL 的解析和编码。在 Python 3 中,urllib2
的功能被整合到 urllib.request
模块中。
- 要点
- 高级请求功能:支持自定义请求头、处理不同的 HTTP 方法(如 POST、PUT、DELETE 等)。
- 异常处理完善:提供了丰富的异常类,方便对不同类型的网络请求错误进行处理。
- 扩展性强:可以通过自定义处理器(如
HTTPHandler
、HTTPSHandler
等)来扩展功能。
python
import urllib2
import urllib
# 发送简单的 GET 请求
response = urllib2.urlopen('https://www.example.com')
html = response.read()
print(html)
# 发送带有自定义请求头的 GET 请求
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
req = urllib2.Request('https://www.example.com', headers=headers)
response = urllib2.urlopen(req)
html = response.read()
print(html)
# 发送 POST 请求
data = urllib.urlencode({'key': 'value'})
req = urllib2.Request('https://www.example.com', data=data)
response = urllib2.urlopen(req)
html = response.read()
print(html)
-
httplib2
库
httplib2
是一个功能强大且高效的 HTTP 客户端库。它提供了简单而灵活的 API,支持 HTTP 和 HTTPS 协议。httplib2
具有缓存机制,可以减少对同一资源的重复请求,提高请求效率。同时,它还支持处理重定向、自定义请求头等功能。
- 要点
-
缓存机制:内置缓存功能,可有效减少网络请求次数,提高性能。
-
跨平台兼容:在不同操作系统和 Python 版本上都能稳定运行。
-
灵活的配置:可以方便地配置请求头、超时时间、代理等参数。
python
import httplib2
# 创建一个 httplib2 客户端实例
http = httplib2.Http()
# 发送简单的 GET 请求
response, content = http.request('https://www.example.com')
html = content.decode('utf-8')
print(html)
# 发送带有自定义请求头的 GET 请求
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
response, content = http.request('https://www.example.com', headers=headers)
html = content.decode('utf-8')
print(html)
# 发送 POST 请求
data = 'key=value'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
response, content = http.request('https://www.example.com', method='POST', body=data, headers=headers)
html = content.decode('utf-8')
print(html)
启用缓存机制:
python
import httplib2
# 创建一个带有缓存的 httplib2 客户端实例
http = httplib2.Http('.cache') # 指定缓存目录
response, content = http.request('https://www.example.com')
html = content.decode('utf-8')
print(html)
- 总结
-
requests
:以简洁易用和功能全面著称,适合大多数常规的网络请求场景。 -
aiohttp
:基于异步 I/O,在高并发场景下性能卓越,还支持 WebSocket 和服务器搭建。 -
urllib
:作为 Python 标准库,提供基础的网络请求功能,适合初学者和简单任务。 -
urllib2
(Python 2 特有):提供高级 HTTP 请求功能,在 Python 3 中被整合到urllib.request
。 -
httplib2
:具有缓存机制,能提高请求效率,配置灵活,适用于对性能有一定要求的场景。
4. 爬取数据后可以使用哪些数据库存储数据的,为什么
MySQL 的优势与适用场景
- 成熟稳定的特性:MySQL 是一款经过广泛使用和验证的关系型数据库,具有高度的稳定性和可靠性。它在数据存储和管理方面表现出色,能够确保数据的完整性和一致性。
- 丰富的功能支持:MySQL 支持事务处理、存储过程、触发器等高级功能,这些功能为复杂的数据处理和业务逻辑实现提供了强大的支持。
- 良好的可扩展性:通过主从复制、集群等技术,MySQL 可以轻松实现高可用性和扩展性,满足不同规模应用的需求。
- 适用场景:当爬取的数据具有明显的结构化特点,并且需要进行复杂的查询和分析时,MySQL 是一个理想的选择。例如,爬取的商品信息等,这些数据通常具有固定的字段和关系,适合存储在关系型数据库中。
MongoDB 的优势与适用场景
- 灵活的数据模型:MongoDB 是一种非关系型数据库,采用文档型数据存储方式,不需要预先定义严格的表结构。这使得它非常适合存储结构多变的数据,能够轻松应对数据结构的动态变化。
- 高可扩展性:MongoDB 具有良好的水平扩展能力,可以通过添加节点来处理大量的数据,满足高并发场景下的数据存储需求。
- 高性能表现:MongoDB 具备快速的读写性能,能够高效地处理实时数据,为应用提供快速的响应。
- 适用场景:当爬取的数据结构不固定,或者需要快速存储和查询大量数据时,MongoDB 是一个不错的选择。例如,爬取的社交媒体数据、日志数据等,这些数据的结构通常比较灵活,不适合存储在传统的关系型数据库中。
5. 用过的爬虫框架或者模块有哪些?有什么优缺点?
Scrapy
框架
- 优点:
- 高效的并发性能:
Scrapy
基于异步 I/O 实现,能够同时处理大量的请求,具有很高的并发性能。它可以在短时间内抓取大量的数据,提高爬虫的效率。 - 丰富的功能特性:
Scrapy
提供了强大的中间件、管道等机制,方便进行请求处理、数据清洗和存储。通过中间件,我们可以对请求和响应进行预处理和后处理;通过管道,我们可以对抓取到的数据进行清洗、验证和存储。 - 良好的可扩展性:
Scrapy
具有高度的可扩展性,我们可以通过编写插件和扩展来满足不同的需求。例如,我们可以编写自定义的下载器中间件来处理反爬虫机制,或者编写自定义的管道来实现特定的数据存储逻辑。
- 高效的并发性能:
- 缺点:
- 较高的学习成本:
Scrapy
框架相对复杂,包含了多个组件和概念,对于初学者来说,需要花费一定的时间来学习和掌握。 - 灵活性相对较差:对于一些简单的爬虫任务,使用
Scrapy
可能会显得过于繁琐,因为它的配置和开发过程相对复杂。
- 较高的学习成本:
BeautifulSoup
模块
- 优点:
- 简单易用的 API:
BeautifulSoup
提供了简洁明了的 API,使得解析 HTML 和 XML 文档变得非常容易。即使是没有太多编程经验的开发者,也能快速上手使用。 - 高度的灵活性:
BeautifulSoup
可以与其他 HTTP 请求库(如requests
)结合使用,适用于各种类型的爬虫任务。我们可以根据需要选择不同的解析器(如html.parser
、lxml
等),以满足不同的解析需求。
- 简单易用的 API:
- 缺点:
- 较低的性能表现:对于大规模的网页解析任务,
BeautifulSoup
的性能相对较低,因为它是基于 Python 实现的,解析速度不如一些专门的解析器。 - 缺乏异步支持:
BeautifulSoup
本身不支持异步操作,在处理大量请求时,效率会受到一定的影响。
- 较低的性能表现:对于大规模的网页解析任务,
6. 写爬虫是用多进程好?还是多线程好?
多进程的优势与劣势
- 优点:
- 充分利用多核 CPU:每个进程都有独立的内存空间,能够充分利用多核 CPU 的优势,并行处理多个任务,从而提高爬虫的并发性能。
- 较高的稳定性:一个进程崩溃不会影响其他进程的运行,因此多进程爬虫在稳定性方面表现较好。
- 缺点:
- 较大的资源消耗:每个进程都需要独立的内存和系统资源,对于资源有限的系统,可能会导致性能下降。
- 复杂的进程间通信:进程间通信需要使用专门的机制(如管道、队列等),实现起来比较复杂,增加了开发的难度。
多线程的优势与劣势
- 优点:
- 资源共享的优势:多个线程可以共享同一进程的内存空间,资源消耗相对较小,能够在一定程度上提高系统的资源利用率。
- 简单的线程间通信:线程间可以直接访问共享变量,通信比较方便,开发难度相对较低。
- 缺点:
- GIL 的限制:Python 的全局解释器锁(GIL)限制了多线程的并发性能,对于 CPU 密集型任务,多线程的优势不明显。
- 较低的稳定性:一个线程崩溃可能会导致整个进程崩溃,因此多线程爬虫在稳定性方面相对较差。
一般来说,对于 I/O 密集型的爬虫任务,多线程或异步编程(如使用 aiohttp
)是更好的选择,因为它们可以在等待 I/O 操作完成时,切换到其他任务,提高效率;对于 CPU 密集型的爬虫任务,多进程可以更好地利用多核 CPU 的性能,充分发挥硬件的优势。
7. 说明常见的反爬虫措施和应对方法
常见反爬虫手段分析
- IP 封禁:网站通过检测频繁的请求 IP,对异常 IP 进行封禁,以防止爬虫过度访问。
- User - Agent 检测:检查请求的 User - Agent 信息,过滤掉不符合要求的请求,确保请求来自合法的浏览器或设备。
- 验证码:要求用户输入验证码,防止自动化程序访问,增加爬虫的识别难度。
- Cookie 和 Session 验证:通过验证 Cookie 和 Session 信息,确保请求的合法性,防止爬虫绕过登录验证。
- JS 渲染:使用 JavaScript 动态生成页面内容,使得爬虫难以直接获取数据,需要模拟浏览器行为才能解析页面。
应对方法详解
- IP 代理的使用:搭建代理 IP 池,定期更换请求 IP,避免因单个 IP 请求过于频繁而被封禁。可以使用免费或付费的代理服务,也可以自己搭建代理服务器。
python
import requests
# 配置代理
proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'http://proxy.example.com:8080'
}
# 发送带有代理的请求
response = requests.get('https://www.example.com', proxies=proxies)
- 随机 User - Agent 的设置:在请求头中设置随机的 User - Agent 信息,模拟不同的浏览器和设备,增加请求的真实性。
python
import requests
import random
# 定义不同的 User - Agent 列表
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36'
]
# 随机选择一个 User - Agent
headers = {
'User - Agent': random.choice(user_agents)
}
# 发送带有随机 User - Agent 的请求
response = requests.get('https://www.example.com', headers=headers)
- 验证码识别技术:使用 OCR 技术(如
pytesseract
)或第三方验证码识别服务(如打码平台)来识别验证码。
python
import pytesseract
from PIL import Image
# 打开验证码图片
image = Image.open('captcha.png')
# 进行灰度处理
image = image.convert('L')
# 识别验证码
captcha_text = pytesseract.image_to_string(image)
print(captcha_text)
- 模拟登录的实现:使用 Session 对象来处理 Cookie 和 Session 信息,模拟用户登录过程,获取有效的登录凭证。
python
import requests
# 登录页面 URL
login_url = 'https://example.com/login'
# 登录表单数据
data = {
'username': 'your_username',
'password': 'your_password'
}
# 创建 Session 对象
session = requests.Session()
# 发送登录请求
response = session.post(login_url, data=data)
# 登录成功后,使用该 Session 发送后续请求
response = session.get('https://example.com/protected_page')
- Selenium 的应用:对于 JS 渲染的页面,可以使用 Selenium 模拟浏览器行为,加载动态生成的页面内容。
python
from selenium import webdriver
# 创建浏览器驱动实例
driver = webdriver.Chrome()
# 打开页面
driver.get('https://www.example.com')
# 获取页面源代码
html = driver.page_source
# 关闭浏览器
driver.quit()
8. 常用网页解析器有哪些
BeautifulSoup
- BeautifulSoup 是 Python 中一个非常流行且功能强大的网页解析库,由 Leonard Richardson 开发。它提供了简单而直观的 API,能够将复杂的 HTML 或 XML 文档转换为树形结构,方便开发者从文档中提取所需的数据。无论文档格式是否规范,BeautifulSoup 都能很好地处理,并且支持多种解析器,开发者可以根据需求选择合适的解析器。
- 要点
- 简单易用:提供了简洁的方法来查找、筛选和提取 HTML/XML 文档中的数据,即使是初学者也能快速上手。
- 支持多种解析器:可以使用
html.parser
(Python 内置的解析器)、lxml
(基于 C 语言的快速解析器)、html5lib
(能够处理不规范 HTML 的解析器)等不同的解析器。 - 灵活性高:可以通过标签名、类名、ID、属性等多种方式定位元素。
python
from bs4 import BeautifulSoup
import requests
# 发送请求获取网页内容
url = 'https://www.example.com'
response = requests.get(url)
html_content = response.text
# 创建 BeautifulSoup 对象
soup = BeautifulSoup(html_content, 'html.parser')
# 通过标签名查找元素
all_links = soup.find_all('a')
for link in all_links:
print(link.get('href'))
# 通过类名查找元素
divs_with_class = soup.find_all('div', class_='example-class')
for div in divs_with_class:
print(div.text)
lxml
-
特点:lxml 是一个高性能的 XML 和 HTML 解析库,它结合了 libxml2 和 libxslt 库的功能,基于 C 语言实现,因此解析速度非常快。lxml 提供了简洁的 API,支持 XPath 和 CSS 选择器,使得开发者可以更方便地定位和提取文档中的元素。当处理大型 HTML 文档时,使用
lxml
解析器可以显著提高解析速度。 -
要点
- 高性能:由于基于 C 语言实现,解析速度比纯 Python 解析器快很多,适合处理大规模的 HTML/XML 数据。
- 支持 XPath 和 CSS 选择器:XPath 是一种强大的路径表达式语言,CSS 选择器则是前端开发中常用的元素选择方式,lxml 同时支持这两种方式,提供了更多的选择。
- 与 Python 标准库兼容:可以与 Python 的标准库(如
urllib
、requests
)很好地结合使用。
python
from lxml import etree
import requests
# 发送请求获取网页内容
url = 'https://www.example.com'
response = requests.get(url)
html_content = response.text
# 创建 HTML 解析器
parser = etree.HTMLParser()
tree = etree.fromstring(html_content, parser)
# 使用 XPath 查找元素
all_links = tree.xpath('//a/@href')
for link in all_links:
print(link)
# 使用 CSS 选择器查找元素
divs_with_class = tree.cssselect('div.example-class')
for div in divs_with_class:
print(etree.tostring(div, encoding='unicode'))
解析 XML 文档并提取特定元素
python
xml_content = '<root><item id="1">Value 1</item><item id="2">Value 2</item></root>'
tree = etree.fromstring(xml_content)
items = tree.xpath('//item[@id="2"]')
for item in items:
print(item.text)
9. 需要登录的网页,如何解决同时限制 IP,Cookie,Session
- IP 限制
代理 IP 的运用:搭建一个代理 IP 池,并且定期更换请求所使用的 IP,这样就能避免因单个 IP 频繁发起请求而被封禁。既可以使用免费或者付费的代理服务,也能够自行搭建代理服务器。
python
import requests
import random
# 定义代理 IP 列表
proxy_list = [
{'http': 'http://proxy1.example.com:8080', 'https': 'http://proxy1.example.com:8080'},
{'http': 'http://proxy2.example.com:8080', 'https': 'http://proxy2.example.com:8080'}
]
# 随机挑选一个代理
proxy = random.choice(proxy_list)
# 目标登录页面 URL
url = 'https://example.com/login'
try:
# 发送请求并使用代理
response = requests.get(url, proxies=proxy)
print(response.text)
except requests.RequestException as e:
print(f"请求过程中出现错误: {e}")
要点:构建代理 IP 池,随机选用代理 IP,避免单一 IP 被封禁。可以进一步优化代理 IP 池,添加代理可用性检测机制,自动剔除不可用的代理。
请求频率的控制:合理设置请求之间的间隔时间,防止在短时间内发送大量请求。可以借助 time.sleep()
函数来达成这一目的。
python
import requests
import time
# 目标登录页面 URL
url = 'https://example.com/login'
for _ in range(5):
try:
# 发送请求
response = requests.get(url)
print(response.text)
except requests.RequestException as e:
print(f"请求过程中出现错误: {e}")
# 每隔 5 秒发送一次请求
time.sleep(5)
要点:设置合理的请求间隔,避免触发网站的请求频率限制。可以根据网站的反爬策略动态调整请求间隔时间,例如通过分析响应头中的相关信息来调整。
- Cookie 和 Session 限制
模拟登录操作:通过深入分析登录页面的请求参数以及请求方式,使用 requests
或者 selenium
来模拟用户的登录过程,从而获取有效的 Cookie 和 Session 信息。
python
import requests
# 登录页面 URL
login_url = 'https://example.com/login'
# 登录所需的表单数据
data = {
'username': 'your_username',
'password': 'your_password'
}
# 创建会话对象
session = requests.Session()
# 发送登录请求
response = session.post(login_url, data=data)
# 登录成功后,使用该会话请求受保护页面
response = session.get('https://example.com/protected_page')
print(response.text)
要点:利用会话对象模拟登录,维持会话状态。可以对登录过程进行封装,以便在多个爬虫任务中复用。
Cookie 和 Session 的更新:当 Cookie 或者 Session 过期时,重新执行登录操作,获取新的 Cookie 和 Session 信息。可以通过检查响应状态码或者特定的页面元素来判断 Cookie 和 Session 是否过期。
python
import requests
# 登录页面 URL
login_url = 'https://example.com/login'
# 受保护页面 URL
protected_url = 'https://example.com/protected_page'
# 登录所需的表单数据
data = {
'username': 'your_username',
'password': 'your_password'
}
# 创建会话对象
session = requests.Session()
def login():
"""
执行登录操作
"""
response = session.post(login_url, data=data)
if response.status_code == 200:
print("登录成功")
else:
print("登录失败")
# 首次登录
login()
# 请求受保护页面
response = session.get(protected_url)
if response.status_code != 200:
print("Cookie 或 Session 可能已过期,重新登录")
# 重新登录
login()
# 再次请求受保护页面
response = session.get(protected_url)
print(response.text)
要点:实时监测 Cookie 和 Session 的有效性,过期时及时重新登录。可以将 Cookie 和 Session 的管理封装成一个类,提供更便捷的操作方法。
10. 如何用 Python 爬虫解决验证码问题?
解决验证码问题的关键在于准确识别验证码内容或者模拟用户操作以通过验证。
简单图片验证码识别(OCR)
pytesseract
库的使用:pytesseract
是基于 Tesseract OCR 引擎的 Python 封装库,能够识别简单的验证码。
python
import pytesseract
from PIL import Image
# 打开验证码图片
image = Image.open('captcha.png')
# 进行灰度处理
image = image.convert('L')
# 识别验证码
captcha_text = pytesseract.image_to_string(image)
print(captcha_text)
- 要点:使用
pytesseract
结合PIL
库进行简单的图片验证码识别。可以尝试不同的 OCR 引擎,如百度 OCR、阿里云 OCR 等,以提高识别准确率。 - 图片预处理操作:为了提升识别准确率,可以对验证码图片进行预处理,例如二值化、降噪等。
python
import pytesseract
from PIL import Image, ImageFilter
# 打开验证码图片
image = Image.open('captcha.png')
# 进行灰度处理
image = image.convert('L')
# 二值化处理
threshold = 127
image = image.point(lambda p: 255 if p > threshold else 0)
# 降噪处理
image = image.filter(ImageFilter.MedianFilter())
# 识别验证码
captcha_text = pytesseract.image_to_string(image)
print(captcha_text)
- 要点:对验证码图片进行预处理,提高 OCR 识别准确率。可以使用更复杂的图像处理算法,如形态学操作、边缘检测等,进一步优化预处理效果。
第三方验证码识别服务
- 打码平台的利用:像超级鹰、云打码等打码平台,提供了验证码识别 API,通过发送验证码图片以及相关参数,就能获取识别结果。
python
import requests
# 超级鹰 API URL
api_url = 'http://upload.chaojiying.net/Upload/Processing.php'
# 打码平台所需的参数
data = {
'user': 'your_username',
'pass2': 'your_password',
'softid': 'your_softid',
'codetype': '1004' # 验证码类型
}
# 打开验证码图片
files = {'userfile': open('captcha.png', 'rb')}
# 发送请求获取识别结果
response = requests.post(api_url, data=data, files=files)
result = response.json()
print(result)
- 要点:借助第三方打码平台的 API 进行验证码识别。可以对比不同打码平台的识别准确率和价格,选择最适合的平台。
机器学习方法
- 自定义验证码识别模型的训练:运用深度学习框架(如 TensorFlow、PyTorch),收集大量的验证码图片以及对应的标签,训练一个验证码识别模型。这种方法需要一定的机器学习知识和大量的训练数据,但识别准确率较高。
python
import tensorflow as tf
from tensorflow.keras import layers, models
# 构建简单的卷积神经网络模型
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')
])
# 编译模型
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 假设已经有训练数据和标签
# train_images, train_labels = ...
# 训练模型
# model.fit(train_images, train_labels, epochs=10)
# 预测验证码
# test_image = ...
# predictions = model.predict(test_image)
- 要点:使用深度学习框架训练自定义的验证码识别模型。可以尝试不同的模型架构,如 ResNet、Inception 等,以提高模型的性能。
模拟用户操作(针对滑动验证码、点击验证码等)
selenium
模拟用户操作:对于滑动验证码和点击验证码,可以使用selenium
模拟用户的鼠标滑动和点击操作。
python
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
# 打开浏览器
driver = webdriver.Chrome()
# 打开目标登录页面
driver.get('https://example.com/login')
# 定位滑动验证码滑块元素
slider = driver.find_element_by_id('slider')
# 模拟鼠标拖动操作
ActionChains(driver).click_and_hold(slider).move_by_offset(200, 0).release().perform()
# 等待 2 秒
time.sleep(2)
# 后续操作...
# 关闭浏览器
driver.quit()
- 要点:使用
selenium
模拟用户的鼠标操作,绕过滑动验证码和点击验证码。可以结合图像识别技术,自动计算滑块的滑动距离或者点击位置,提高自动化程度。
友情提示:本文已经整理成文档,可以到如下链接免积分下载阅读
https://download.csdn.net/download/ylfhpy/90420645