Skip to content

Commit 1245075

Browse files
committed
fix: httpx proxy format error
feat: add a ip proxy provider
1 parent 0024ce6 commit 1245075

File tree

14 files changed

+1241
-1070
lines changed

14 files changed

+1241
-1070
lines changed

config/base_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
IP_PROXY_POOL_COUNT = 2
2424

2525
# 代理IP提供商名称
26-
IP_PROXY_PROVIDER_NAME = "kuaidaili"
26+
IP_PROXY_PROVIDER_NAME = "kuaidaili" # kuaidaili | wandouhttp
2727

2828
# 设置为True不会打开浏览器(无头浏览器)
2929
# 设置False会打开一个浏览器

docs/static/images/wd_http_img.png

369 KB
Loading
345 KB
Loading
295 KB
Loading
331 KB
Loading

docs/代理使用.md

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,11 @@
55

66
![代理 IP 使用流程图](static/images/代理IP%20流程图.drawio.png)
77

8-
## 准备代理 IP 信息
9-
点击 <a href="https://www.kuaidaili.com/?ref=ldwkjqipvz6c">快代理</a> 官网注册并实名认证(国内使用代理 IP 必须要实名,懂的都懂)
108

11-
## 获取 IP 代理的密钥信息
12-
从 <a href="https://www.kuaidaili.com/?ref=ldwkjqipvz6c">快代理</a> 官网获取免费试用,如下图所示
13-
![img.png](static/images/img.png)
9+
## 选择一个代理IP提供商
1410

15-
注意:选择私密代理
16-
![img_1.png](static/images/img_1.png)
17-
18-
选择开通试用
19-
![img_2.png](static/images/img_2.png)
20-
21-
初始化一个快代理的示例,如下代码所示,需要4个参数
22-
23-
```python
24-
25-
def new_kuai_daili_proxy() -> KuaiDaiLiProxy:
26-
"""
27-
构造快代理HTTP实例
28-
Returns:
29-
30-
"""
31-
return KuaiDaiLiProxy(
32-
kdl_secret_id=os.getenv("kdl_secret_id", "你的快代理secert_id"),
33-
kdl_signature=os.getenv("kdl_signature", "你的快代理签名"),
34-
kdl_user_name=os.getenv("kdl_user_name", "你的快代理用户名"),
35-
kdl_user_pwd=os.getenv("kdl_user_pwd", "你的快代理密码"),
36-
)
37-
38-
```
39-
在试用的订单中可以看到这四个参数,如下图所示
40-
41-
`kdl_user_name``kdl_user_pwd`
42-
![img_3.png](static/images/img_3.png)
43-
44-
`kdl_secret_id``kdl_signature`
45-
![img_4.png](static/images/img_4.png)
46-
47-
## 将配置文件中的`ENABLE_IP_PROXY`置为 `True`
48-
> `IP_PROXY_POOL_COUNT` 池子中 IP 的数量
11+
### 快代理
12+
[快代理使用文档](快代理使用文档.md)
4913

14+
### 豌豆HTTP文档查看
15+
[豌豆HTTP使用文档](豌豆HTTP使用文档.md)

docs/快代理使用文档.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
## 快代理使用文档(支持个人和企业用户)
2+
3+
## 准备代理 IP 信息
4+
点击 <a href="https://www.kuaidaili.com/?ref=ldwkjqipvz6c">快代理</a> 官网注册并实名认证(国内使用代理 IP 必须要实名,懂的都懂)
5+
6+
## 获取 IP 代理的密钥信息
7+
从 <a href="https://www.kuaidaili.com/?ref=ldwkjqipvz6c">快代理</a> 官网获取免费试用,如下图所示
8+
![img.png](static/images/img.png)
9+
10+
注意:选择私密代理
11+
![img_1.png](static/images/img_1.png)
12+
13+
选择开通试用
14+
![img_2.png](static/images/img_2.png)
15+
16+
初始化一个快代理的示例,如下代码所示,需要4个参数
17+
18+
```python
19+
# 文件地址: proxy/providers/kuai_daili_proxy.py
20+
# -*- coding: utf-8 -*-
21+
def new_kuai_daili_proxy() -> KuaiDaiLiProxy:
22+
"""
23+
构造快代理HTTP实例
24+
Returns:
25+
26+
"""
27+
return KuaiDaiLiProxy(
28+
kdl_secret_id=os.getenv("kdl_secret_id", "你的快代理secert_id"),
29+
kdl_signature=os.getenv("kdl_signature", "你的快代理签名"),
30+
kdl_user_name=os.getenv("kdl_user_name", "你的快代理用户名"),
31+
kdl_user_pwd=os.getenv("kdl_user_pwd", "你的快代理密码"),
32+
)
33+
34+
```
35+
在试用的订单中可以看到这四个参数,如下图所示
36+
37+
`kdl_user_name``kdl_user_pwd`
38+
![img_3.png](static/images/img_3.png)
39+
40+
`kdl_secret_id``kdl_signature`
41+
![img_4.png](static/images/img_4.png)

docs/豌豆HTTP使用文档.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## 豌豆HTTP代理使用文档 (只支持企业用户)
2+
3+
## 准备代理 IP 信息
4+
点击 <a href="https://h.wandouip.com?invite_code=rtnifi">豌豆HTTP代理</a> 官网注册并实名认证(国内使用代理 IP 必须要实名,懂的都懂)
5+
6+
## 获取 IP 代理的密钥信息 appkey
7+
从 <a href="https://h.wandouip.com?invite_code=rtnifi">豌豆HTTP代理</a> 官网获取免费试用,如下图所示
8+
![img.png](static/images/wd_http_img.png)
9+
10+
选择自己需要的套餐
11+
![img_4.png](static/images/wd_http_img_4.png)
12+
13+
14+
初始化一个豌豆HTTP代理的示例,如下代码所示,需要1个参数: app_key
15+
16+
```python
17+
# 文件地址: proxy/providers/wandou_http_proxy.py
18+
# -*- coding: utf-8 -*-
19+
20+
def new_wandou_http_proxy() -> WanDouHttpProxy:
21+
"""
22+
构造豌豆HTTP实例
23+
Returns:
24+
25+
"""
26+
return WanDouHttpProxy(
27+
app_key=os.getenv(
28+
"wandou_app_key", "你的豌豆HTTP app_key"
29+
), # 通过环境变量的方式获取豌豆HTTP app_key
30+
)
31+
32+
```
33+
34+
在个人中心的`开放接口`找到 `app_key`,如下图所示
35+
36+
![img_2.png](static/images/wd_http_img_2.png)
37+
38+

proxy/providers/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
# @Time : 2024/4/5 10:13
1515
# @Desc :
1616
from .jishu_http_proxy import new_jisu_http_proxy
17-
from .kuaidl_proxy import new_kuai_daili_proxy
17+
from .kuaidl_proxy import new_kuai_daili_proxy
18+
from .wandou_http_proxy import new_wandou_http_proxy
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# 声明:本代码仅供学习和研究目的使用。使用者应遵守以下原则:
2+
# 1. 不得用于任何商业用途。
3+
# 2. 使用时应遵守目标平台的使用条款和robots.txt规则。
4+
# 3. 不得进行大规模爬取或对平台造成运营干扰。
5+
# 4. 应合理控制请求频率,避免给目标平台带来不必要的负担。
6+
# 5. 不得用于任何非法或不当的用途。
7+
#
8+
# 详细许可条款请参阅项目根目录下的LICENSE文件。
9+
# 使用本代码即表示您同意遵守上述原则和LICENSE中的所有条款。
10+
11+
# -*- coding: utf-8 -*-
12+
# @Author : [email protected]
13+
# @Time : 2025/7/31
14+
# @Desc : 豌豆HTTP 代理IP实现
15+
import os
16+
from typing import Dict, List
17+
from urllib.parse import urlencode
18+
19+
import httpx
20+
21+
from proxy import IpCache, IpGetError, ProxyProvider
22+
from proxy.types import IpInfoModel
23+
from tools import utils
24+
25+
26+
class WanDouHttpProxy(ProxyProvider):
27+
28+
def __init__(self, app_key: str, num: int = 100):
29+
"""
30+
豌豆HTTP 代理IP实现
31+
:param app_key: 开放的app_key,可以通过用户中心获取
32+
:param num: 单次提取IP数量,最大100
33+
"""
34+
self.proxy_brand_name = "WANDOUHTTP"
35+
self.api_path = "https://api.wandouapp.com/"
36+
self.params = {
37+
"app_key": app_key,
38+
"num": num,
39+
}
40+
self.ip_cache = IpCache()
41+
42+
async def get_proxy(self, num: int) -> List[IpInfoModel]:
43+
"""
44+
:param num:
45+
:return:
46+
"""
47+
48+
# 优先从缓存中拿 IP
49+
ip_cache_list = self.ip_cache.load_all_ip(
50+
proxy_brand_name=self.proxy_brand_name
51+
)
52+
if len(ip_cache_list) >= num:
53+
return ip_cache_list[:num]
54+
55+
# 如果缓存中的数量不够,从IP代理商获取补上,再存入缓存中
56+
need_get_count = num - len(ip_cache_list)
57+
self.params.update({"num": min(need_get_count, 100)}) # 最大100
58+
ip_infos = []
59+
async with httpx.AsyncClient() as client:
60+
url = self.api_path + "?" + urlencode(self.params)
61+
utils.logger.info(f"[WanDouHttpProxy.get_proxy] get ip proxy url:{url}")
62+
response = await client.get(
63+
url,
64+
headers={
65+
"User-Agent": "MediaCrawler https://github.com/NanmiCoder/MediaCrawler",
66+
},
67+
)
68+
res_dict: Dict = response.json()
69+
if res_dict.get("code") == 200:
70+
data: List[Dict] = res_dict.get("data", [])
71+
current_ts = utils.get_unix_timestamp()
72+
for ip_item in data:
73+
ip_info_model = IpInfoModel(
74+
ip=ip_item.get("ip"),
75+
port=ip_item.get("port"),
76+
user="", # 豌豆HTTP不需要用户名密码认证
77+
password="",
78+
expired_time_ts=utils.get_unix_time_from_time_str(
79+
ip_item.get("expire_time")
80+
),
81+
)
82+
ip_key = f"WANDOUHTTP_{ip_info_model.ip}_{ip_info_model.port}"
83+
ip_value = ip_info_model.model_dump_json()
84+
ip_infos.append(ip_info_model)
85+
self.ip_cache.set_ip(
86+
ip_key, ip_value, ex=ip_info_model.expired_time_ts - current_ts
87+
)
88+
else:
89+
error_msg = res_dict.get("msg", "unknown error")
90+
# 处理具体错误码
91+
error_code = res_dict.get("code")
92+
if error_code == 10001:
93+
error_msg = "通用错误,具体错误信息查看msg内容"
94+
elif error_code == 10048:
95+
error_msg = "没有可用套餐"
96+
raise IpGetError(f"{error_msg} (code: {error_code})")
97+
return ip_cache_list + ip_infos
98+
99+
100+
def new_wandou_http_proxy() -> WanDouHttpProxy:
101+
"""
102+
构造豌豆HTTP实例
103+
Returns:
104+
105+
"""
106+
return WanDouHttpProxy(
107+
app_key=os.getenv(
108+
"wandou_app_key", "你的豌豆HTTP app_key"
109+
), # 通过环境变量的方式获取豌豆HTTP app_key
110+
)

0 commit comments

Comments
 (0)