1. 古籍目录采集的价值与挑战
去年参与一个文化研究项目时,我需要整理3000多条散落在各地图书馆网站的古籍目录信息。手动复制粘贴到第三天,手腕已经酸痛到需要贴膏药的程度。这种重复劳动让我开始思考:为什么不用Python爬虫把这些公开数据自动化采集下来?
古籍目录作为文化遗产的数字化入口,通常包含书名、作者、版本、馆藏地等关键元数据。这些信息对研究者而言就像寻宝地图,但分散在各个文化机构的网站中,呈现形式也五花八门——有的用表格展示,有的藏在JavaScript动态加载的页面里,还有的甚至需要翻越十几层分页才能看到完整列表。
典型的文化资源目录页面特征:
- 分页导航(通常隐藏总页数)
- 动态加载(Ajax/JSON接口)
- 表格与非结构化文本混合
- 反爬措施(请求频率限制)
我曾遇到某省级图书馆的目录系统,每次翻页都会更换URL中的token参数,前5页用page=1~5,到第6页突然变成start=25&limit=5。这种"捉迷藏"式的设计,正是我们需要用技术手段解决的痛点。
2. 环境配置与工具选型
工欲善其事,必先利其器。经过多个项目的对比测试,我总结出这套稳定高效的爬虫工具链:
python复制# 核心依赖
import requests # 比urllib更人性化的HTTP库
from bs4 import BeautifulSoup # HTML解析神器
import pandas as pd # 数据结构化处理
from tqdm import tqdm # 进度条可视化
import time # 请求间隔控制
# 进阶配置
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'zh-CN,zh;q=0.9'
}
为什么选择这些工具?
requests相比标准库的urllib有更简洁的API,自动处理连接池和keep-aliveBeautifulSoup的lxml解析器速度比html.parser快30倍以上pandas的DataFrame能直接输出Excel/CSV,适合非技术背景的研究者使用
重要提示:在爬取前务必检查目标网站的robots.txt文件。例如国家图书馆的robots.txt明确规定:
Disallow: /search/
这类目录就不应强行爬取,建议转向各省市图书馆的开放数据接口。
3. 分页抓取的实战策略
古籍目录最常见的分页模式有三种,每种都需要不同的处理技巧:
3.1 基础分页模式
python复制def get_page_basic(url_template, max_page):
results = []
for page in tqdm(range(1, max_page+1)):
url = url_template.format(page)
try:
response = requests.get(url, headers=HEADERS)
soup = BeautifulSoup(response.text, 'lxml')
# 解析表格数据的代码...
time.sleep(1.5) # 礼貌性延迟
except Exception as e:
print(f"第{page}页抓取失败: {str(e)}")
return pd.DataFrame(results)
关键细节:
- 使用
tqdm包裹循环可显示进度条 time.sleep建议设置在1-3秒区间- URL模板如
"http://example.com/list?page={}"
3.2 动态加载分页
遇到Ajax加载的页面时,需要分析网络请求:
python复制def get_page_ajax(api_url):
params = {
'pageSize': 20,
'pageNum': 1,
'type': '古籍'
}
all_items = []
while True:
response = requests.get(api_url, params=params, headers=HEADERS)
data = response.json()
if not data['list']:
break
all_items.extend(data['list'])
params['pageNum'] += 1
return pd.DataFrame(all_items)
3.3 点击加载更多
对于"加载更多"按钮的页面,可以模拟点击事件:
python复制from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
driver = webdriver.Chrome()
driver.get(start_url)
while True:
try:
more_btn = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "load-more"))
)
more_btn.click()
time.sleep(2) # 等待数据加载
except:
break
soup = BeautifulSoup(driver.page_source, 'lxml')
4. 数据清洗与结构化
原始HTML数据就像刚出土的文物,需要仔细清理:
python复制def clean_data(raw_df):
# 处理缺失值
df = raw_df.fillna('未知')
# 统一日期格式
df['出版日期'] = pd.to_datetime(df['出版日期'], errors='coerce')
# 提取朝代信息
df['朝代'] = df['作者'].str.extract(r'((.*?))')
# 去除HTML标签
df['摘要'] = df['摘要'].str.replace(r'<[^>]+>', '', regex=True)
return df
常见问题处理:
- 合并多列相同含义数据(如"作者"/"撰者")
- 处理特殊字符(□表示缺字的处理)
- 识别并统一不同版本的名称(如"红楼梦"与"石头记")
5. 反爬应对方案
在连续抓取某高校图书馆目录时,我的IP曾被封禁24小时。后来通过以下策略稳定运行:
基础防护:
python复制# 随机User-Agent
def get_random_ua():
ua_list = [...]
return {'User-Agent': random.choice(ua_list)}
# 代理IP池
PROXIES = [
{'http': 'http://123.123.123.123:8888'},
# ...
]
response = requests.get(url, headers=get_random_ua(),
proxies=random.choice(PROXIES))
高级技巧:
- 使用
requests.Session()保持会话 - 自动识别验证码(需配合OCR服务)
- 分布式爬虫架构(Scrapy+Redis)
6. 完整项目示例
以国家哲学社会科学文献中心为例的完整流程:
python复制class AncientBookSpider:
def __init__(self):
self.base_url = "http://www.ncpssd.org"
self.result = []
def parse_page(self, html):
soup = BeautifulSoup(html, 'lxml')
items = soup.select('.book-list li')
for item in items:
data = {
'title': item.select_one('h3').get_text(strip=True),
'author': item.select_one('.author').get_text(strip=True),
'dynasty': re.search(r'\[(.*?)\]', item.text).group(1),
'url': self.base_url + item.a['href']
}
self.result.append(data)
def run(self):
for page in range(1, 6): # 示范只抓5页
url = f"{self.base_url}/category?page={page}"
response = requests.get(url, headers=HEADERS)
self.parse_page(response.text)
time.sleep(2)
return pd.DataFrame(self.result)
输出结果示例:
| 书名 | 作者 | 朝代 | 详情页链接 |
|---|---|---|---|
| 论语集注 | 朱熹 | 宋 | http://... |
| 史记 | 司马迁 | 汉 | http://... |
7. 法律与伦理边界
在兴奋地抓取数据时,有次差点踩到法律红线。某商业数据库的条款明确规定禁止自动化采集,幸好被同事及时提醒。现在我的检查清单包括:
- 确认robots.txt规则
- 检查网站用户协议
- 控制请求频率(>1秒/次)
- 不绕过付费墙
- 标注数据来源
文化数据的合理使用应该像图书馆借阅——既充分获取知识,又尊重资源提供者的权益。建议将采集的数据仅用于个人研究,若需公开发布,最好联系数据所有者获取授权。
