news 2026/10/8 12:18:40

用Python爬取Top100电视剧并存入MySQL:TaoToken统一Key通道下的采集与入库实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Python爬取Top100电视剧并存入MySQL:TaoToken统一Key通道下的采集与入库实战

1. 从榜单页到数据库:Python 爬取 Top100 电视剧并写入 MySQL 的完整链路

很多人第一次做爬虫练手,都会选「榜单类」页面:结构规整、字段清晰、数据量不大,正好适合把「请求 → 解析 → 清洗 → 入库」这条链路走一遍。这次要做的就是把 Top100 电视剧榜单抓下来,存进 MySQL,方便后面做排序、筛选、导出 Excel 之类的操作。核心检索词就三个:python、爬取、mysql 数据库,整篇文章围绕这三件事展开。

适合谁看?如果你已经会写for循环、装过 Python 包,但还没完整跑通过一次「采集 + 落库」,这篇就是给你准备的。我会把每一步拆开:先建表,再写采集脚本,然后处理空值、分页、编码这些坑,最后用 SQL 核对数据。全程用requests+BeautifulSoup+pymysql,不引入重框架,复制就能跑。

另外说一句,采集脚本里如果涉及调用大模型做字段清洗、简介摘要、导演名归一化,我会用 TaoToken 的统一 Key 通道来演示,这样你不用在多个平台之间来回切 Key。下面正式开始。

2. 环境准备与 TaoToken 统一 Key 通道配置(python 爬虫 mysql 入库前置)

2.1 先装依赖,别急着写代码

打开终端,建一个干净的虚拟环境,避免和系统里的包打架:

python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate pip install requests beautifulsoup4 pymysql lxml

lxml是解析器,比默认的html.parser快,遇到不规范 HTML 也更稳。装完可以用pip list确认一下版本。

2.2 MySQL 侧的准备

本地装好 MySQL 后,先建库:

CREATE DATABASE tv_top100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

注意用utf8mb4,不要用老的utf8。电视剧名里偶尔会有生僻字或特殊符号,utf8mb4能少踩很多编码坑。建完库,记下 host、port、user、password,后面脚本里要用。

2.3 TaoToken 统一 Key 通道是什么,为什么这里要用

采集本身不需要大模型,但实际项目里,榜单数据往往要做二次加工:比如把「导演:xxx」这种带前缀的字段拆干净、把简介压缩成一句话、把主演列表标准化。这些用规则写会越写越乱,交给模型做反而省事。

TaoToken 提供的是一个统一 Key 通道:你拿一个 Key,就能在同一个入口调用不同模型,不用为每个模型单独申请账号、单独配 Base URL。对爬虫项目来说,好处是清洗逻辑可以集中在一处,脚本里只维护一个 Key。

配置入口在这里:

  • 控制台拿 Key:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api_keys
  • 接入文档(看 Base URL 和参数格式):https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc

API 基础地址是https://taotoken.net/api,注意这个地址后面不加任何查询参数。Key 拿到后不要硬编码进脚本,用环境变量存:

# macOS / Linux export TAOTOKEN_API_KEY="你的Key" # Windows PowerShell $env:TAOTOKEN_API_KEY="你的Key"

这样脚本可以提交到 Git 而不泄露凭证。下面进入建表和采集部分。

3. 建表 SQL 与可复制采集脚本(python 爬取电视剧写入 mysql 数据库)

3.1 建表:字段类型要留余量

先建表。字段设计上,movie_name用varchar(100),导演和主演可能有多人,给到varchar(200),简介用varchar(500)更保险,因为有些简介比想象中长:

USE tv_top100; CREATE TABLE movies7 ( m_id INT PRIMARY KEY AUTO_INCREMENT, movie_name VARCHAR(100) NOT NULL, movie_daoyan VARCHAR(200) NULL, movie_zhuyan VARCHAR(200) NOT NULL, movie_jianjie VARCHAR(500) NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我额外加了created_at,方便后面判断数据是哪次采集的。movie_jianjie允许为 NULL,因为榜单里确实存在没有简介的条目,这点很关键,后面脚本里要专门判断。

3.2 采集脚本:分页 + 空值判断 + 批量入库

下面这份脚本可以直接复制,改掉数据库密码和库名即可。我把分页、空值判断、异常捕获都写进去了:

import os import time import requests import pymysql from bs4 import BeautifulSoup DB_CONFIG = { "host": "127.0.0.1", "port": 3306, "user": "root", "passwd": "你的数据库密码", "db": "tv_top100", "charset": "utf8mb4", } HEADERS = { "User-Agent": ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/122.0.0.0 Safari/537.36" ), "Referer": "http://www.mtime.com/top/tv/top100/", "Accept-Language": "zh-CN,zh;q=0.9", } BASE_URL = "http://www.mtime.com/top/tv/top100/index-{}.html" def fetch_page(page: int) -> str: url = BASE_URL.format(page) resp = requests.get(url, headers=HEADERS, timeout=10) resp.raise_for_status() resp.encoding = "utf-8" return resp.text def parse_page(html: str): soup = BeautifulSoup(html, "lxml") container = soup.find("div", class_="top_list") if container is None: return [] rows = [] for film in container.find_all("li"): h2 = film.find("h2") if h2 is None: continue name = h2.get_text(strip=True) ps = film.find_all("p") daoyan = ps[0].get_text(strip=True) if len(ps) > 0 else "" zhuyan = ps[1].get_text(strip=True) if len(ps) > 1 else "" jianjie_tag = film.find("p", class_="mt3") jianjie = jianjie_tag.get_text(strip=True) if jianjie_tag is not None else "" rows.append((name, daoyan, zhuyan, jianjie)) return rows def save_rows(conn, rows): sql = ( "INSERT INTO movies7 (movie_name, movie_daoyan, movie_zhuyan, movie_jianjie) " "VALUES (%s, %s, %s, %s)" ) with conn.cursor() as cursor: cursor.executemany(sql, rows) conn.commit() def main(): conn = pymysql.connect(**DB_CONFIG) total = 0 try: for page in range(1, 6): html = fetch_page(page) rows = parse_page(html) if rows: save_rows(conn, rows) total += len(rows) print(f"page {page} -> {len(rows)} rows") time.sleep(1.5) finally: conn.close() print(f"done, total {total} rows")

几个细节说明一下。第一,resp.encoding = "utf-8"要显式设置,否则requests有时会猜错编码,导致中文变乱码。第二,executemany比循环单条execute快很多,100 条数据一次提交,减少网络往返。第三,time.sleep(1.5)是礼貌间隔,别把对方服务器打崩,也降低被限流的概率。

3.3 用 TaoToken 做字段清洗(可选但推荐)

如果榜单里导演字段带「导演:」前缀,或者简介里有换行、多余空格,可以用模型统一清洗。下面这段是调用示例,Base URL 用https://taotoken.net/api:

import os import requests def clean_field(raw_text: str) -> str: api_key = os.environ["TAOTOKEN_API_KEY"] payload = { "model": "gpt-4o-mini", "messages": [ {"role": "system", "content": "你是数据清洗助手,只输出清洗后的纯文本,不要解释。"}, {"role": "user", "content": f"去掉前缀和多余空白,保留人名或简介:{raw_text}"}, ], "temperature": 0, } resp = requests.post( "https://taotoken.net/api/v1/chat/completions", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, json=payload, timeout=30, ) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"].strip()

注意choices这个字段,如果返回结构不对,多半是请求体格式或模型名写错了,后面排障章节会讲。清洗逻辑建议放在入库前,先清洗再executemany,避免脏数据进库。

4. 运行验证与数据核对(python 爬虫 mysql 落库结果检查)

4.1 跑脚本,看输出

保存为spider.py,运行:

python spider.py

正常输出类似:

page 1 -> 20 rows page 2 -> 20 rows page 3 -> 20 rows page 4 -> 20 rows page 5 -> 20 rows done, total 100 rows

如果某一页返回 0 行,先别慌,可能是那一页结构不同,或者被限流返回了验证页。把fetch_page返回的 HTML 存下来看一眼就知道。

4.2 用 SQL 核对数据

进 MySQL 客户端,跑几条核对语句:

-- 总数 SELECT COUNT(*) FROM movies7; -- 看前 10 条 SELECT m_id, movie_name, movie_daoyan, movie_zhuyan FROM movies7 LIMIT 10; -- 找空简介 SELECT COUNT(*) FROM movies7 WHERE movie_jianjie IS NULL OR movie_jianjie = ''; -- 找重复剧名 SELECT movie_name, COUNT(*) AS c FROM movies7 GROUP BY movie_name HAVING c > 1;

如果总数是 100,说明分页抓全了。如果空简介数量和你预期不符,回去检查jianjie_tag的判断逻辑。重复剧名可能是榜单本身就有,也可能是脚本跑了两次,加个唯一索引或者先清表再跑就能解决。

4.3 验证 TaoToken 通道是否通

单独测一下清洗接口,确认 Key 和 Base URL 都对:

curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"回复ok"}]}'

返回里能看到choices数组和内容,就说明通道正常。想直接在网页里试模型效果,可以用模型对话入口:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=model_chat

5. 常见报错排查:401、local proxy failed、reading choices、OAuth

5.1 401 Unauthorized

最常见的原因是 Key 没读到。检查环境变量:

echo $TAOTOKEN_API_KEY

如果是空的,说明当前终端没加载。Windows 下用$env:TAOTOKEN_API_KEY查看。还有一种情况是 Key 复制时带了空格或换行,strip()一下再拼进 Header。

5.2 local proxy failed

这个报错通常出现在请求发不出去的时候,本质是网络层没通。先确认目标地址能访问:

curl -I https://taotoken.net/api

如果这里就失败,说明本机网络或 DNS 有问题,检查一下网络设置,别在代码里硬塞代理配置。代码里requests默认会读系统环境变量里的代理设置,如果之前设过又忘了清,也会报这个错。用proxies={"http": None, "https": None}显式关掉即可。

5.3 reading 'choices' / KeyError: 'choices'

这个报错说明返回的 JSON 里没有choices字段。原因一般有三类:一是请求体格式不对,比如messages写成了字符串;二是模型名写错,服务端返回了错误对象;三是 Key 无效,返回的是鉴权错误。排查方法很简单,把原始返回打出来:

print(resp.status_code) print(resp.text)

看到具体错误信息,基本就能定位。别直接resp.json()["choices"],先判断状态码。

5.4 OAuth 相关报错

如果你用的是某些命令行工具(比如 Claude Code 这类),可能会遇到 OAuth 登录失败。这类工具通常需要配置三件套:Base URL、Key、Model ID。以 Claude Code 为例,配置项写在settings.json里:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "你的Key", "ANTHROPIC_MODEL": "claude-3-5-sonnet-20241022" } }

三件套缺一不可。Base URL 写错、Key 过期、Model ID 拼错,都会报 OAuth 或鉴权失败。如果你用的是 Codex 类工具,配置写在auth.json里,字段名不同但逻辑一样。Cline 的 MCP 配置也是同理,Base URL + Key + Model ID 三件套对齐就行。

5.5 入库报错:Incorrect string value

这个多半是字符集问题。确认三处:建库时用了utf8mb4、建表时用了utf8mb4、连接时charset="utf8mb4"。三处一致基本就不会报。如果还有问题,检查是不是有 emoji 或特殊符号,utf8mb4是能存的,老的utf8不行。

6. 把采集链路固定下来:长期跑批与 Coding Plan

脚本跑通一次不难,难的是长期稳定跑。我的做法是把采集逻辑封装成函数,加一个定时任务,每天跑一次,入库前先按movie_name去重。这样榜单更新时,新数据自动进来,老数据不重复。

如果你后面想把这条链路扩展成「采集 + 模型清洗 + 自动摘要 + 定时入库」的完整流水线,调用量会上来,这时候用 Coding Plan 会更划算,额度集中管理,不用每次单独算。入口在这里:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding_plan

最后留一个实用技巧:采集脚本里所有可能变化的配置(URL、表名、字段映射)都抽成常量放文件顶部,下次换榜单只改几行,不用翻整个脚本。数据库密码和 Key 一律走环境变量,别写死在代码里。这两条做到了,你的爬虫脚本就能从「练手」变成「能长期用」的工具。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 12:17:59

智能供电:移动出行与边缘系统的核心竞争力

做过移动出行和边缘系统的人,大概都会有同一种感受:很多事故和体验翻车,表面上是软件算法、硬件算力的问题,根子上其实是供电没伺候明白。一辆电动车冬季续航打折打到六成,原因不止是电池冷,还有加热系统、…

作者头像 李华
网站建设 2026/10/8 12:17:23

长沙宠物美容培训学校哪家课程好

在长沙寻找优质的宠物美容培训学校?作为湖南省内稀缺的全品类行业认证考点,长沙三生石宠物美容学校凭借权威资质、顶尖师资和硬核教学成果,已成为宠物美容培训行业的标杆之选。一、行业权威认证,湖南唯一双考点长沙三生石宠物美容…

作者头像 李华
网站建设 2026/10/8 12:16:13

superpowers技能库:让AI编程助手告别重复提示词,走向工程化工作流

想给 AI 助手装上“外挂”,superpowers 是我今年试过的最实在的一套技能扩展方案。它不是某个大厂的云端产品,而是一套开源技能库:把日常开发中反复出现的需求拆分、代码审查、测试生成、仓库巡检等流程,封装成一个一个可复用的 s…

作者头像 李华