admin 管理员组文章数量: 1087649
我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南
一、创建隔离开发环境
1. 使用虚拟环境(推荐venv
)
# 在项目目录打开终端执行
python -m venv douban_env # 创建虚拟环境
source douban_env/bin/activate # Linux/macOS激活
douban_env\Scripts\activate # Windows激活
2. 安装依赖库
pip install requests beautifulsoup4 lxml
3. 生成依赖清单
pip freeze > requirements.txt
二、项目架构设计
douban_top250/
├── config/ # 配置文件
│ └── settings.py
├── core/ # 核心逻辑
│ ├── spider.py
│ └── storage.py
├── utils/ # 工具函数
│ └── helper.py
├── output/ # 输出目录
├── main.py # 主入口
└── requirements.txt # 依赖清单
三、分步实现
步骤1:创建配置文件 config/settings.py
# 请求配置
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': 'https://movie.douban/'
}
# 目标URL配置
BASE_URL = 'https://movie.douban/top250'
# 存储配置
OUTPUT_DIR = './output'
CSV_HEADERS = ['标题', '评分', '年份', '国家', '类型', '链接']
# 容错配置
SAFE_MODE = True # 遇到错误时跳过条目而不是终止
UNKNOWN_PLACEHOLDER = "未知" # 数据缺失时的占位符
步骤2:编写工具类 utils/helper.py
import random
import time
def random_delay(min=1, max=3):
"""随机延迟防止被封"""
time.sleep(random.uniform(min, max))
def make_soup(html):
"""创建BeautifulSoup对象"""
from bs4 import BeautifulSoup
return BeautifulSoup(html, 'lxml')
步骤3:核心爬虫逻辑 core/spider.py
import requests
from config import settings
from utils.helper import random_delay, make_soup
class DoubanSpider:
def __init__(self):
self.session = requests.Session()
self.session.headers.update(settings.HEADERS)
def fetch_page(self, url):
"""获取页面内容"""
try:
random_delay()
response = self.session.get(url)
response.raise_for_status() # 自动处理HTTP错误
return response.text
except requests.RequestException as e:
print(f"请求失败: {str(e)}")
return None
def parse_page(self, html):
"""改进后的解析方法"""
soup = make_soup(html)
movies = []
for item in soup.find_all('div', class_='item'):
try:
# 标题与链接
title = item.find('span', class_='title').text.strip()
rating = item.find('span', class_='rating_num').text.strip()
link = item.find('a')['href']
# 详细信息解析(稳健版)
info_div = item.find('div', class_='bd')
info_text = info_div.p.get_text(" ", strip=True) # 用空格替代换行
# 使用正则表达式提取年份/国家/类型
import re
pattern = r'(\d{4})[^/]*(.*?)\s+/\s+(.*?)$'
match = re.search(pattern, info_text)
if match:
year = match.group(1).strip()
country = match.group(2).strip().replace('/', ' ') # 处理国家中的斜杠
genre = match.group(3).strip()
else:
year = country = genre = "N/A" # 无法解析时填充默认值
movies.append({
'标题': title,
'评分': rating,
'年份': year,
'国家': country,
'类型': genre,
'链接': link
})
except Exception as e:
print(f"解析条目失败: {str(e)}")
continue # 跳过当前条目
return movies
def get_all_pages(self):
"""处理分页"""
all_movies = []
start = 0
while True:
url = f"{settings.BASE_URL}?start={start}"
html = self.fetch_page(url)
if not html:
break
movies = self.parse_page(html)
if not movies:
break
all_movies.extend(movies)
start += 25
# 检查是否还有下一页
if start >= 250: # Top250最多250条
break
return all_movies
步骤4:数据存储模块 core/storage.py
import csv
import json
import os
from config import settings
class DataStorage:
@staticmethod
def save_csv(data, filename='douban_top250.csv'):
os.makedirs(settings.OUTPUT_DIR, exist_ok=True)
path = os.path.join(settings.OUTPUT_DIR, filename)
with open(path, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=settings.CSV_HEADERS)
writer.writeheader()
writer.writerows(data)
print(f"数据已保存至 {path}")
@staticmethod
def save_json(data, filename='douban_top250.json'):
os.makedirs(settings.OUTPUT_DIR, exist_ok=True)
path = os.path.join(settings.OUTPUT_DIR, filename)
with open(path, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"数据已保存至 {path}")
步骤5:主程序 main.py
from core.spider import DoubanSpider
from core.storage import DataStorage
def main():
# 检查robots协议
print("豆瓣 robots.txt 重要条款:")
print("User-agent: *")
print("Disallow: /search") # 实际需查看最新内容
# 执行爬虫
spider = DoubanSpider()
movies_data = spider.get_all_pages()
# 存储数据
if movies_data:
DataStorage.save_csv(movies_data)
DataStorage.save_json(movies_data)
else:
print("未获取到有效数据")
if __name__ == '__main__':
main()
四、运行与验证
- 在激活的虚拟环境中执行:
python main.py
- 检查
output/
目录生成的 CSV 和 JSON 文件
五、高级优化建议
- 异常处理增强:
# 在spider类中添加重试机制
def fetch_page(self, url, retries=3):
for attempt in range(retries):
try:
# ...原有代码...
except requests.RequestException as e:
if attempt == retries - 1:
raise
print(f"重试中 ({attempt+1}/{retries})...")
time.sleep(2 ** attempt) # 指数退避
- 请求头轮换:
# 在settings.py中添加多个User-Agent
USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]
# 在helper.py中添加选择函数
def get_random_user_agent():
return random.choice(settings.USER_AGENTS)
- 代理设置(如果需要):
# 在spider初始化时添加
def __init__(self, proxy=None):
if proxy:
self.session.proxies = {'http': proxy, 'https': proxy}
六、法律合规检查
- 访问 https://www.douban/robots.txt 查看协议
- 重点条款:
User-agent: *
Disallow: /subject_search
Disallow: /amazon_search
Disallow: /search
Disallow: /group/search
Disallow: /event/search
Disallow: /forum/search
Disallow: /game/search
- 合规措施:
- 限制请求频率(代码中已实现随机延迟)
- 不绕过反爬机制
- 仅用于学习用途
- 不存储敏感信息
通过这个结构化的项目实现,你可以:
- 保持代码的可维护性
- 方便后续扩展功能(如添加代理支持)
- 符合Python最佳实践
- 有效管理依赖项
下一步可以尝试:
- 添加日志记录模块
- 实现数据库存储(MySQL/MongoDB)
- 使用Scrapy框架重构项目
- 部署到服务器定时运行
版权声明:本文标题:我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://roclinux.cn/b/1749807595a2764333.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论