scrapy 遇到人机验证 如何通过中间件和pyexecjs来处理
时间: 2024-11-11 22:32:27 浏览: 32
Scrapy遇到网站的人机验证通常涉及到JavaScript执行,因为很多验证码需要实时浏览器环境才能识别。为了处理这种情况,你可以利用中间件(Middleware)配合`pyexecjs`库来解决。以下是一个基本的步骤:
1. 安装必要的库:
- Scrapy本身
- `scrapy-splash`(一个中间件,支持渲染JavaScript)
- `pyexecjs`(用于在服务器端执行JavaScript)
```bash
pip install scrapy scrapy-splash pyexecjs
```
2. 设置`settings.py`文件:
- 将`splash`设置为Scrapy爬虫的支持中间件
- 配置Splash的URL
- 关闭Scrapy默认的HTTP客户端,因为它可能会干扰JS渲染
```python
SPIDER_MIDDLEWARES = {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
# 其他中间件...
}
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': None, # 关闭内置压缩中间件
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'yourproject.middlewares.YourCustomJsMiddleware': 800, # 自定义中间件处理验证码
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, # 可能需要移除或自定义User-Agent
# ...
}
SPLASH_URL = 'http://localhost:8050' # 根据你的 Splash 实例地址替换
```
3. 创建自定义中间件 `YourCustomJsMiddleware`:
- 这里可以使用`pyexecjs`加载并执行JavaScript代码来获取验证码值。
- 当请求包含JavaScript需要处理的URL时,中间件会暂停下载,执行JS,并将结果返回给爬虫。
```python
import execjs
from scrapy import Request
class YourCustomJsMiddleware:
def process_request(self, request, spider):
if 'captcha_url' in request.meta and request.url.startswith(request.meta['captcha_url']):
js_code = """
// 你的JS代码片段,例如从网页上获取验证码
var captcha = document.getElementById('captcha').innerText;
return captcha;
"""
with execjs.get() as engine:
captcha_value = engine.eval(js_code)
# 将验证码值保存到响应头或元数据中
request.meta['captcha'] = captcha_value
# 如果有API可以提交验证码,创建一个新的POST请求替换原来的GET请求
submit_captcha_url = "https://your-captcha-api.com/submit"
submit_request = Request(submit_captcha_url, meta={'captcha': captcha_value}, callback=self.submit_callback)
# 返回POST请求替换原请求
return submit_request
def submit_callback(self, response):
# 检查验证码是否通过,然后继续抓取下一个页面
pass # 根据API响应更新状态
```
4. 在爬虫中发送带验证码的请求:
在Spider中,设置请求的时候加上`meta`属性,比如验证码URL。
```python
def start_requests(self):
yield Request("https://your-start-page", meta={'captcha_url': 'https://with-captcha-url'}, callback=self.parse)
# ...其他逻辑...
def parse(self, response):
# 在解析阶段检查是否有验证码,并使用之前保存的值
captcha_value = response.meta.get('captcha')
if captcha_value is not None:
# 对于每个需要验证码的链接,添加新的请求
for link in links_to_follow(response):
yield Request(link, meta={'captcha': captcha_value})
```
阅读全文