最近在做一个Python爬虫项目,目标是抓取网络上的笑话内容。这个看似简单的需求背后其实涉及不少技术细节,今天就来分享一下我的实现过程和踩过的坑。
作为一个经常需要放松的程序员,收集一些轻松幽默的笑话是个不错的主意。通过Python爬虫自动抓取笑话内容,不仅可以练习爬虫技术,还能给自己建个笑话库,一举两得。下面我会详细介绍从环境准备到最终实现的完整流程。
Python生态中有多个成熟的爬虫框架,经过对比我最终选择了Requests+BeautifulSoup的组合:
安装依赖:
bash复制pip install requests beautifulsoup4
选择目标网站时需要考虑几个因素:
经过筛选,我选择了几个笑话更新频繁且结构清晰的网站作为数据源。这里特别提醒:一定要遵守网站的robots.txt协议,控制爬取频率。
基础请求代码:
python复制import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
def get_page(url):
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
response.encoding = response.apparent_encoding
return response.text
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
return None
关键点说明:
不同网站的笑话结构各异,需要针对性编写解析逻辑。以某笑话网站为例:
python复制def parse_jokes(html):
soup = BeautifulSoup(html, 'html.parser')
jokes = []
for item in soup.select('.joke-item'):
title = item.select_one('.title').text.strip()
content = item.select_one('.content').text.strip()
jokes.append({'title': title, 'content': content})
return jokes
解析时常见问题:
根据需求可以考虑多种存储方式:
| 存储方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| TXT文件 | 简单 | 不易查询 | 临时存储 |
| CSV | 结构化 | 无索引 | 中小规模 |
| SQLite | 功能全 | 需学习SQL | 本地应用 |
| MongoDB | 灵活 | 需安装 | 大型项目 |
我最终选择了SQLite,平衡了功能复杂度和学习成本。
python复制import sqlite3
def init_db():
conn = sqlite3.connect('jokes.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS jokes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
source TEXT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
def save_joke(joke):
conn = sqlite3.connect('jokes.db')
cursor = conn.cursor()
cursor.execute('INSERT INTO jokes (title, content, source) VALUES (?, ?, ?)',
(joke['title'], joke['content'], joke.get('source', '')))
conn.commit()
conn.close()
目标网站可能采取的反爬措施:
实际项目中采用的策略:
time.sleep(random.uniform(1, 3))python复制import time
import random
def crawl_with_delay(url):
time.sleep(random.uniform(1, 3)) # 随机延迟1-3秒
return get_page(url)
当需要爬取大量页面时,可以考虑:
已经实现基础功能后,可以进一步:
python复制# 定时任务示例
import schedule
import time
def daily_crawl():
print("开始每日定时爬取...")
# 爬取逻辑
schedule.every().day.at("10:00").do(daily_crawl)
while True:
schedule.run_pending()
time.sleep(1)
中文字符处理常见错误:
解决方案:
python复制# 强制指定编码
response.encoding = 'gbk' # 或utf-8等
# 数据库连接时指定编码
conn = sqlite3.connect('jokes.db', detect_types=sqlite3.PARSE_DECLTYPES)
网站改版导致选择器失效的应对:
重要提醒:
最终项目目录结构示例:
code复制joke_crawler/
├── main.py # 主程序
├── config.py # 配置文件
├── utils/
│ ├── crawler.py # 爬取逻辑
│ ├── parser.py # 解析逻辑
│ └── storage.py # 存储逻辑
├── data/
│ └── jokes.db # 数据库文件
└── requirements.txt # 依赖列表
关键文件示例(requirements.txt):
code复制requests==2.28.1
beautifulsoup4==4.11.1
sqlalchemy==1.4.41
schedule==1.1.0
经过上述实现,爬虫可以稳定运行并收集笑话数据。一些统计信息:
示例查询代码:
python复制def search_jokes(keyword):
conn = sqlite3.connect('jokes.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM jokes WHERE title LIKE ? OR content LIKE ?',
(f'%{keyword}%', f'%{keyword}%'))
results = cursor.fetchall()
conn.close()
return results
在开发这个爬虫项目的过程中,我积累了一些宝贵经验:
对于想要学习爬虫的新手,我的建议是从简单项目开始,逐步增加复杂度。这个笑话爬虫就是个不错的起点,涵盖了请求发送、页面解析、数据存储等爬虫核心技能。