林芝市网站建设_网站建设公司_产品经理_seo优化
2026/1/14 0:19:43 网站建设 项目流程

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 - 综合实战爬虫与可视化下(待更新)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询