从维基百科爬取名人种族信息的技术实现需求
针对900万演员维基百科种族信息爬取的解决方案
针对你要处理900万演员维基百科种族信息的研究需求,这里分享一套高效、合规的实现方案——毕竟量级这么大,得兼顾性能和准确性:
核心思路
- 优先用维基百科API而非网页爬取:API更稳定合规,能直接获取结构化数据,避免解析HTML的麻烦,还能降低被反爬限制的风险。
- 批量异步处理:900万数据量单线程完全不可行,必须用异步请求+批次处理来提升效率。
- 严格匹配预定义种族集合:只从你指定的集合中提取匹配项,避免无关数据干扰研究结果。
具体实现步骤
1. 数据预处理
先对900万演员列表做清洗,减少无效请求:
- 去重:用集合或数据库去重,避免重复查询同一个演员。
- 标准化名字格式:统一大小写、去掉冗余后缀(如
Jr.、III)、修正拼写错误(可借助模糊匹配工具提前处理),提升维基百科API的匹配准确率。
2. 维基百科API数据获取
使用MediaWiki官方API来获取演员页面的infobox信息(维基百科人物页的infobox通常包含ethnicity字段):
- 核心API接口:
https://en.wikipedia.org/w/api.php - 关键参数:
action=query:指定查询操作titles=演员名字:要查询的页面标题prop=infoboxes:获取页面的infobox数据format=json:返回JSON格式的结构化数据
3. 种族信息提取与匹配
从API返回的infobox中提取ethnicity字段内容,再与你的预定义种族集合做匹配:
- 提取逻辑:遍历infobox的字段,找到
name为ethnicity(不区分大小写)的字段,取出其value值。 - 匹配逻辑:将提取的种族文本与预定义集合做模糊匹配(比如忽略大小写、处理复合种族如
Italian-American时匹配集合中的Italian和American),只保留集合内的项。
4. 批量异步与性能优化
- 异步请求:用Python的
aiohttp库实现异步HTTP请求,同时控制并发数(建议每秒不超过50次,符合维基百科API的Rate Limit要求)。 - 本地缓存:用Redis或本地数据库缓存已查询过的演员结果,避免重复请求。
- 分批处理:将900万列表分成每批次1000-5000个演员,分批异步处理,同时将结果写入数据库(如PostgreSQL、SQLite),防止程序中断丢失数据。
示例代码片段(Python)
import aiohttp import asyncio from typing import List, Dict # 你的预定义种族集合 PREDEFINED_ETHNICITIES = ['American', 'GreaterEuropean', 'British', 'WestEuropean', 'Italian'] async def fetch_actor_ethnicity(session: aiohttp.ClientSession, actor_name: str) -> List[str]: """单个演员的种族信息查询与匹配""" api_url = "https://en.wikipedia.org/w/api.php" params = { "action": "query", "titles": actor_name, "prop": "infoboxes", "format": "json", "formatversion": 2 # 使用更简洁的JSON格式 } async with session.get(url=api_url, params=params) as resp: if resp.status != 200: return [] data = await resp.json() pages = data.get("query", {}).get("pages", []) if not pages or pages[0].get("missing"): return [] # 未找到对应页面 # 遍历infobox字段找ethnicity infoboxes = pages[0].get("infoboxes", []) for infobox in infoboxes: for field in infobox.get("fields", []): if field.get("name", "").lower() == "ethnicity": ethnicity_text = field.get("value", "").lower() # 匹配预定义种族集合 matched_eth = [ eth for eth in PREDEFINED_ETHNICITIES if eth.lower() in ethnicity_text ] return list(set(matched_eth)) # 去重 return [] async def process_actor_batch(actor_names: List[str]) -> Dict[str, List[str]]: """处理一批演员的种族查询""" # 设置合规的User-Agent,标明你的项目信息 headers = {"User-Agent": "EthnicityResearchProject/1.0 (your-research-email@example.com)"} async with aiohttp.ClientSession(headers=headers) as session: tasks = [fetch_actor_ethnicity(session, name) for name in actor_names] results = await asyncio.gather(*tasks) return dict(zip(actor_names, results)) # 测试示例 async def main(): sample_actors = ['Chris Hemsworth', 'Paul Walker', 'Al Pacino'] batch_result = await process_actor_batch(sample_actors) for actor, eth in batch_result.items(): print(f"{actor}: {eth if eth else '未找到匹配种族'}") if __name__ == "__main__": asyncio.run(main())
关键注意事项
- 合规性:维基百科API允许非商业研究使用,但必须设置清晰的
User-Agent,不要超过请求频率限制(可参考维基百科API文档的Rate Limit规则)。 - 数据准确性:部分演员页面可能没有种族信息,或信息模糊,这类数据建议标记为“未知”;对于复合种族(如
Irish-American),需根据你的研究需求决定是否匹配多个预定义项。 - 错误处理:添加请求超时、重试机制,处理API返回的错误状态码,避免程序因个别请求失败而中断。
内容的提问来源于stack exchange,提问作者Shivam




