python利用html.parser爬取豆瓣top250并存储到本地
时间: 2025-06-12 12:07:03 浏览: 15
<think>嗯,用户想用Python的html.parser模块来抓取豆瓣Top250的电影列表,然后保存到本地文件。首先,我需要回忆一下html.parser的基本用法,因为通常大家可能更常用BeautifulSoup或者lxml这样的库,但用户明确要求使用html.parser,这可能是因为他们不想依赖第三方库,或者想练习标准库的使用。
首先,我需要确定如何用html.parser解析HTML文档。html.parser模块中的HTMLParser类可以用来处理标记化的数据,通过重写它的方法,比如handle_starttag、handle_data等,来提取需要的信息。但是,处理嵌套的标签可能会比较麻烦,需要维护一些状态变量来跟踪当前所在的标签结构。
接下来,我需要分析豆瓣Top250页面的结构。根据之前的引用,每个电影条目都在<li class="item">标签里。每个条目包含的信息比如标题、评分、评价数等,这些信息可能分布在不同的标签和类名中。例如,标题可能在<span class="title">里,评分在<span class="rating_num">里,评价数可能在<div class="star">里的一个<span>里。
用户提到使用html.parser,所以需要手动解析这些结构。可能需要定义一个解析器类,继承自HTMLParser,并在其中处理标签和数据。例如,当遇到<li class="item">时,开始记录一个电影条目,然后在内部遇到需要的标签时提取相应的数据。
另外,分页处理也是需要考虑的。豆瓣Top250有10页,每页25个电影,所以需要循环构造URL,比如https://movie.douban.com/top250?start=0,然后每次增加25,直到250。
保存数据到本地文件,用户可能需要的是CSV或者Excel格式。根据引用中的例子,其他方法用了Excel,这里可能需要用csv模块来写入CSV文件,或者使用pandas库,但用户可能希望尽量减少依赖,所以csv模块更合适。
在代码结构上,可能需要以下步骤:
1. 发送HTTP请求获取页面内容,注意设置请求头模拟浏览器访问,避免被反爬虫拦截。
2. 使用自定义的HTMLParser子类来解析页面内容,提取所需数据。
3. 处理分页,循环获取所有页面的数据。
4. 将提取的数据保存到CSV文件中。
需要注意的问题包括:
- 处理异常和网络请求的错误,比如添加重试机制。
- 遵守豆瓣的robots.txt,设置合理的请求间隔,避免被封IP。
- 确保提取的数据准确,可能需要调试解析器是否正确处理了标签嵌套和数据位置。
- 编码问题,保存文件时使用正确的编码如utf-8。
另外,用户可能没有提到但需要考虑的是,有些电影的外文名可能不存在,这时候需要处理缺失数据的情况,避免程序出错。例如,当<span class="title">只有一个时,外文名可能不存在,此时可以留空或者用默认值填充。
总结步骤:
1. 定义解析器类,跟踪需要的标签和数据。
2. 循环处理每一页的URL。
3. 发送请求获取HTML内容。
4. 使用解析器提取数据。
5. 将数据写入CSV文件。
现在需要把这些思路转化为具体的代码,并确保html.parser的正确使用。可能需要定义状态变量,比如current_tag来跟踪是否在目标标签内,然后提取相应的数据。例如,当进入<span class="title">时,记录接下来的数据作为标题,但需要区分中文名和外文名,外文名可能在第二个<span class="title">里,且可能包含斜杠或其他符号。此外,评分和评价数也需要类似的逻辑处理。
测试代码时,可能需要打印中间结果,确保数据正确提取。另外,处理分页时,URL参数是否正确构造也需要验证。
最后,保存到本地文件时,确保文件正确关闭,数据正确写入,并且格式正确,比如表头是否有中文字段,各列是否对齐。</think>以下是使用Python标准库`html.parser`模块抓取豆瓣Top250电影数据并保存到本地文件的完整实现步骤:
---
### 一、实现步骤
#### 1. 发送HTTP请求
使用`urllib.request`发送带请求头的GET请求,避免被反爬:
```python
from urllib.request import Request, urlopen
import csv
def fetch_html(url):
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
req = Request(url, headers=headers)
return urlopen(req).read().decode('utf-8')
```
#### 2. 定义HTML解析器
继承`HTMLParser`类,通过标签层级提取数据:
```python
from html.parser import HTMLParser
class DoubanParser(HTMLParser):
def __init__(self):
super().__init__()
self.movies = []
self.current_movie = {}
self.in_item = False # 是否在<li class="item">中
self.in_title = False # 是否在标题标签中
self.in_rating = False # 是否在评分标签中
self.in_votes = False # 是否在评价数标签中
def handle_starttag(self, tag, attrs):
attrs = dict(attrs)
if tag == 'li' and attrs.get('class') == 'item':
self.in_item = True
self.current_movie = {}
elif self.in_item:
if tag == 'span' and attrs.get('class') == 'title':
self.in_title = True
elif tag == 'span' and attrs.get('class') == 'rating_num':
self.in_rating = True
elif tag == 'div' and attrs.get('class') == 'star':
self.in_votes = True
def handle_data(self, data):
if self.in_title:
if '中文名' not in self.current_movie:
self.current_movie['中文名'] = data.strip()
else:
self.current_movie['外文名'] = data.strip().replace('/', '').strip()
elif self.in_rating:
self.current_movie['评分'] = data.strip()
elif self.in_votes and '评价数' not in self.current_movie:
self.current_movie['评价数'] = data.strip().replace('人评价', '')
def handle_endtag(self, tag):
if tag == 'li' and self.in_item:
self.in_item = False
if self.current_movie: # 确保数据完整
self.movies.append(self.current_movie)
elif tag == 'span' and self.in_title:
self.in_title = False
elif tag == 'span' and self.in_rating:
self.in_rating = False
elif tag == 'div' and self.in_votes:
self.in_votes = False
```
#### 3. 处理分页与数据保存
```python
def save_to_csv(data, filename):
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=['中文名', '外文名', '评分', '评价数'])
writer.writeheader()
writer.writerows(data)
def main():
all_movies = []
for page in range(0, 250, 25): # 共10页
url = f'https://movie.douban.com/top250?start={page}'
html = fetch_html(url)
parser = DoubanParser()
parser.feed(html)
all_movies.extend(parser.movies)
print(f'已爬取第{page//25+1}页数据')
save_to_csv(all_movies, 'douban_top250.csv')
print('数据已保存至douban_top250.csv')
if __name__ == '__main__':
main()
```
---
### 二、关键点说明
1. **反爬策略**
- 使用`User-Agent`伪装浏览器访问[^3]
- 每次请求间隔可添加`time.sleep(2)`降低频率
2. **数据完整性处理**
通过`in_item`等状态变量确保数据采集在正确的标签层级内[^4]
3. **编码问题**
保存CSV时使用`utf-8-sig`编码,避免Excel打开乱码
---
### 三、扩展优化建议
1. **异常处理**
添加`try-except`块处理网络请求超时
2. **数据清洗**
使用正则表达式过滤特殊字符:`import re; re.sub(r'[\n\t]', '', data)`
3. **异步请求**
改用`aiohttp`库提升爬取效率
---
阅读全文
相关推荐


















