Python Requests代理爬虫
使用Requests显式传入代理配置,BeautifulSoup解析Quotes to Scrape。代码处理连接超时、可重试状态码、分页、限速和UTF-8结构化输出。
语言Python 3.10+框架Requests + BeautifulSoup测试目标Quotes to Scrape输出quotes.jsonl
01
END-TO-END RESULT
采集静态分页页面并输出JSON Lines
测试目标Quotes to Scrape
https://quotes.toscrape.com/
运行时Python 3.10+Requests + BeautifulSoup
输出文件结构化数据quotes.jsonl
代码直接连接隧道代理固定网关 proxy.123proxy.cn:36923。主机与端口无需替换,出口路由由当前产品配置决定;你只需设置控制台生成的完整代理用户名和密码。
02
CREDENTIALS
只把代理账密放进环境变量
PROXY_USER必须是控制台中的代理用户名,不是网站登录手机号。地区和SESSION场景应复制控制台生成的完整路由用户名。
export PROXY_USER="替换为控制台代理用户名"
export PROXY_PASS="替换为控制台代理密码"
# 隧道代理固定网关:proxy.123proxy.cn:36923$env:PROXY_USER="替换为控制台代理用户名"
$env:PROXY_PASS="替换为控制台代理密码"
# 隧道代理固定网关:proxy.123proxy.cn:36923
不要把真实代理密码提交到Git仓库、镜像、日志或前端代码中。
03
COMPLETE PROGRAM
requests_spider.py
以下代码包含完整入口和输出逻辑。安装注释、运行命令与依赖声明保留在文件顶部,复制为对应文件后即可执行。
# requirements:
# python -m pip install requests beautifulsoup4
import json
import os
import time
from urllib.parse import quote, urljoin
import requests
from bs4 import BeautifulSoup
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
PROXY_HOST = "proxy.123proxy.cn"
PROXY_PORT = 36923
PROXY_USER = os.environ["PROXY_USER"]
PROXY_PASS = os.environ["PROXY_PASS"]
START_URL = "https://quotes.toscrape.com/"
MAX_PAGES = 3
proxy_user = quote(PROXY_USER, safe="")
proxy_pass = quote(PROXY_PASS, safe="")
proxy_url = (
f"http://{proxy_user}:{proxy_pass}@{PROXY_HOST}:{PROXY_PORT}"
)
proxies = {"http": proxy_url, "https": proxy_url}
retry = Retry(
total=3,
backoff_factor=1,
status_forcelist=(429, 500, 502, 503, 504),
allowed_methods=("GET",),
)
session = requests.Session()
session.headers.update({
"User-Agent": "123Proxy-Developer-Example/1.0",
"Accept-Language": "en-US,en;q=0.8",
})
session.mount("https://", HTTPAdapter(max_retries=retry))
records = []
url = START_URL
for page_number in range(1, MAX_PAGES + 1):
response = session.get(
url,
proxies=proxies,
timeout=(15, 30),
)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
for quote_node in soup.select("div.quote"):
records.append({
"text": quote_node.select_one("span.text").get_text(strip=True),
"author": quote_node.select_one("small.author").get_text(strip=True),
"tags": [
node.get_text(strip=True)
for node in quote_node.select("a.tag")
],
"source_url": url,
})
next_link = soup.select_one("li.next > a")
if not next_link:
break
url = urljoin(url, next_link["href"])
time.sleep(0.5)
with open("quotes.jsonl", "w", encoding="utf-8") as output:
for record in records:
output.write(json.dumps(record, ensure_ascii=False) + "\n")
print(f"saved {len(records)} records to quotes.jsonl")
04
ENGINEERING CHECKS
案例没有省略的关键逻辑
01代理URL中的用户名和密码经过URL编码
02每次请求显式传入proxies,避免被系统代理覆盖
03只重试GET及429、5xx临时错误
04最多采集3页并输出一行一个JSON对象
05
SWITCH PROXY PRODUCT
替换网关,不改采集逻辑
代理产品网关域名端口适合任务
隧道代理
proxy.123proxy.cn36923混合池 / 纯住宅池隧道住宅代理
residential.123proxy.cn33000国家地区与SESSION不限量动态住宅
unlimit.residential.123proxy.cn10253不限流量住宅任务两类静态代理
控制台分配的固定代理IP返回端口直连IP,无网关域名隧道住宅代理的国家与SESSION写在完整代理用户名中
网关固定为 residential.123proxy.cn:33000。例如使用美国SESSION时,直接把控制台生成的完整用户名作为 PROXY_USER,代码无需解析或重组。
06
PRIMARY REFERENCES
框架文档与测试目标
07
TROUBLESHOOTING
常见问题
为什么没有只设置Session.proxies?
Requests官方文档说明环境代理可能覆盖Session级配置。案例在每次请求中显式传入proxies,行为更可控。
如何切换到隧道住宅代理?
将代码中的固定接入地址改为residential.123proxy.cn:33000,并把控制台生成的完整地区或SESSION用户名放入PROXY_USER。
如何扩大分页数量?
先验证目标授权、robots规则和任务速率,再调整MAX_PAGES与请求间隔。