news 2026/3/10 18:07:08

Day 35:【99天精通Python】综合实战 - 爬虫与数据分析可视化(上) - 数据采集与入库

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Day 35:【99天精通Python】综合实战 - 爬虫与数据分析可视化(上) - 数据采集与入库

Day 35:【99天精通Python】综合实战 - 爬虫与数据分析可视化(上) - 数据采集与入库

前言

欢迎来到第35天!

经过前两周的学习,我们已经掌握了网络请求(Requests)、网页解析(BeautifulSoup)、数据库操作(SQLite)、日志记录(Logging)以及多线程等进阶技能。

现在,是时候把这些"珍珠"串成一条项链了。

接下来的两天,我们将完成一个全栈级的数据分析小项目

  1. 数据采集 (Day 35):编写爬虫,抓取豆瓣电影 Top250的完整数据(250条)。
  2. 数据存储 (Day 35):将清洗后的数据存入SQLite数据库。
  3. 数据分析与可视化 (Day 36):从数据库读取数据,分析评分分布、年代分布,并生成漂亮的图表。

今天,我们的任务是:把数据搬回家!


一、项目架构设计

为了写出专业范儿的代码,我们不再把所有逻辑塞进一个文件,而是采用模块化设计

1.1 目录结构

movie_project/ ├── main.py # 程序入口 ├── spider.py # 爬虫逻辑 (Requests + BS4) ├── storage.py # 数据库逻辑 (SQLite) ├── movie.db # (自动生成) 数据库文件 └── app.log # (自动生成) 日志文件

1.2 技术栈

  • 网络请求:requests(伪装 UA, 处理分页)
  • 网页解析:BeautifulSoup(CSS 选择器)
  • 数据存储:sqlite3
  • 日志记录:logging(记录抓取进度和错误)
  • 防反爬:time.sleep(随机延时)

二、第一步:数据库模块 (storage.py)

我们需要一个类来管理数据库连接,负责初始化表结构和保存数据。

# storage.pyimportsqlite3importloggingclassDBManager:def__init__(self,db_name="movie.db"):self.conn=sqlite3.connect(db_name)self.cursor=self.conn.cursor()self.create_table()defcreate_table(self):"""初始化表结构"""sql=""" CREATE TABLE IF NOT EXISTS movies ( id INTEGER PRIMARY KEY AUTOINCREMENT, rank INTEGER, title TEXT, rating REAL, quote TEXT, link TEXT ); """self.cursor.execute(sql)self.conn.commit()definsert_movie(self,movie_data):"""插入一条电影数据"""try:sql="INSERT INTO movies (rank, title, rating, quote, link) VALUES (?, ?, ?, ?, ?)"self.cursor.execute(sql,(movie_data['rank'],movie_data['title'],movie_data['rating'],movie_data['quote'],movie_data['link']))self.conn.commit()exceptExceptionase:logging.error(f"数据插入失败:{movie_data['title']}-{e}")defclose(self):self.conn.close()

三、第二步:爬虫模块 (spider.py)

这是核心部分。我们需要处理分页(Top250 共 10 页,每页 25 条),并且要注意提取时的容错处理。

# spider.pyimportrequestsfrombs4importBeautifulSoupimporttimeimportrandomimportloggingclassMovieSpider:def__init__(self):self.base_url="https://movie.douban.com/top250"self.headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"}defget_html(self,url):"""发送请求获取HTML"""try:resp=requests.get(url,headers=self.headers,timeout=10)ifresp.status_code==200:returnresp.textelse:logging.warning(f"请求失败{url}: 状态码{resp.status_code}")returnNoneexceptExceptionase:logging.error(f"请求异常{url}:{e}")returnNonedefparse_html(self,html):"""解析HTML,生成电影数据生成器"""soup=BeautifulSoup(html,'lxml')items=soup.select('.item')foriteminitems:try:# 1. 排名rank=int(item.select_one('.pic em').get_text())# 2. 标题 (取第一个标题,通常是中文名)title=item.select_one('.info .title').get_text()# 3. 评分rating=float(item.select_one('.rating_num').get_text())# 4. 引言 (可能不存在)quote_tag=item.select_one('.inq')quote=quote_tag.get_text()ifquote_tagelse""# 5. 链接link=item.select_one('.pic a')['href']yield{'rank':rank,'title':title,'rating':rating,'quote':quote,'link':link}exceptExceptionase:logging.error(f"解析条目出错:{e}")continuedefstart_crawl(self,db_manager):"""开始抓取所有页面"""logging.info("爬虫启动...")# 豆瓣Top250共10页,参数 start=0, 25, 50 ... 225foriinrange(0,250,25):url=f"{self.base_url}?start={i}"logging.info(f"正在抓取页面:{url}")html=self.get_html(url)ifhtml:formovieinself.parse_html(html):# 存入数据库db_manager.insert_movie(movie)logging.info(f"已保存:{movie['rank']}.{movie['title']}")# 随机休眠 1-3 秒,防止被封IPtime.sleep(random.uniform(1,3))logging.info("所有页面抓取完成!")

四、第三步:程序入口 (main.py)

最后,我们将日志配置好,并将两个模块组装起来。

# main.pyimportloggingfromstorageimportDBManagerfromspiderimportMovieSpider# 配置日志:同时输出到文件和控制台logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s',handlers=[logging.FileHandler("app.log",encoding='utf-8'),logging.StreamHandler()])defmain():# 1. 初始化数据库db=DBManager()try:# 2. 初始化爬虫spider=MovieSpider()# 3. 开始工作spider.start_crawl(db)exceptExceptionase:logging.critical(f"程序发生严重错误:{e}",exc_info=True)finally:# 4. 关闭数据库连接db.close()logging.info("程序退出。")if__name__=="__main__":main()

五、运行效果与检查

运行main.py后,你会看到控制台不断输出抓取进度:

2026-02-03 10:00:01 - INFO - 爬虫启动... 2026-02-03 10:00:01 - INFO - 正在抓取页面: https://movie.douban.com/top250?start=0 2026-02-03 10:00:02 - INFO - 已保存: 1. 肖申克的救赎 2026-02-03 10:00:02 - INFO - 已保存: 2. 霸王别姬 ...

运行结束后,检查目录下的movie.db文件。你可以使用DB Browser for SQLite打开它,确认表里是否有了 250 条数据。


六、常见问题

Q1:爬到一半报错停止了怎么办?

网络请求是不稳定的。

  1. 重试机制:可以在get_html中增加一个while循环,如果请求失败,等待几秒后重试(最多3次)。
  2. 断点续传:每次抓取前,先查询数据库里最大的rank是多少,然后从那一页开始抓。

Q2:lxml解析器报错?

如果没有安装lxml,可以将BeautifulSoup(html, 'lxml')改为BeautifulSoup(html, 'html.parser')(Python内置,无需安装,但稍慢)。

Q3:被豆瓣封了 IP (403 Forbidden)?

如果你请求太快(没有 sleep),豆瓣会暂时封禁你的 IP。
解决方法:

  1. 加大time.sleep的时间。
  2. 使用手机热点(切换IP)。
  3. 使用代理 IP 池(进阶内容)。

七、小结

今天我们通过一个完整的项目,实践了以下技能:

  1. 面向对象设计:将数据库操作和爬虫逻辑封装成类,职责分明。
  2. 数据采集:利用 Requests 和 BeautifulSoup 批量抓取分页数据。
  3. 数据持久化:将非结构化的网页数据清洗为结构化的数据库记录。
  4. 工程化思维:加入了日志记录和异常处理,使程序更健壮。

明天 (Day 36),我们将取出这些数据,扮演"数据分析师"的角色,看看这 250 部经典电影里到底藏着什么秘密!


系列导航

  • 上一篇:Day 34 - 单元测试Unittest
  • 下一篇:Day 36 - 综合实战爬虫与可视化下(待更新)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/10 16:36:51

Day 38:【99天精通Python】线程池与进程池 - 优雅地管理并发

Day 38:【99天精通Python】线程池与进程池 - 优雅地管理并发 前言 欢迎来到第38天! 在 Day 24 和 Day 25 中,我们学习了如何手动创建线程 (threading.Thread) 和进程 (multiprocessing.Process)。虽然原理都懂了,但在实际工程中&a…

作者头像 李华
网站建设 2026/3/8 14:17:54

【计算机毕业设计案例】基于python_CNN卷积神经网络对猫狗识别基于python_CNN深度学习卷积神经网络对猫狗识别

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/3/5 7:12:03

电商api实战解析:1688.item_get_company 获取公司档案信息

一、接口定位item_get_company 不是“商品级”接口,而是“供应商级”接口。 输入:1688 商品 offerId 或 companyId(二选一) 输出:公司档案 60 字段,包括工商信息、深度认证、工厂能力、贸易能力、在线表现 …

作者头像 李华
网站建设 2026/3/9 15:39:19

【课程设计/毕业设计】基于python_CNN深度学习卷积神经网络对猫狗识别基于深度学习卷积神经网络对猫狗识别

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/3/9 21:30:24

【课程设计/毕业设计】基于python人工智能深度学习对狗表情训练识别基于深度学习对狗表情训练识别

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华