豆瓣是中国的一个社区网站,创立于2005年3月6日,以书影音起家,提供关于书籍、电影、音乐等作品的信息。其中,豆瓣电影Top250榜单是其“明星产品”,被网友誉为“人生必看电影清单”。本文将从BeautifulSoup简介,具体代码步骤和对应逻辑,以及完整的代码实现三部分向您详细介绍如何使用 Python 中的 BeautifulSoup 爬取豆瓣电影Top250榜单。
本文中的代码操作将基于 Python 实现,并建议您使用 Anaconda Jupyter Notebook 作为代码的编辑器。实现爬虫的完整代码已经放置在文章结尾。
BeautifulSoup 是一个 Python 包,功能包括解析 HTML 和 XML 文档、修复含有未闭合标签等错误的文档。这个扩展包为待解析的页面建立一棵树,以便提取其中的数据。BeautifulSoup 本身并不提供网络连接功能,它通常与像 requests 这样的HTTP库一起使用,以便从网络上获取 HTML 或 XML 内容,并随后使用 BeautifulSoup 来解析这些数据。
目前,BeautifulSoup常被用于网页爬虫、数据抓取、自动化测试等场景中。这是BeautifulSoup的官方参考文档:Beautiful Soup Documentation — Beautiful Soup 4.12.0 documentation
在使用Python对豆瓣电影Top250榜单之前,我们需要明确爬取的目标网站和需要的信息。
首先,可以使用如下命令在您的电脑中安装如下的Python包:BeautifulSoup(用于解析 HTML 数据)、requests(用于发送 HTTP 请求)、pandas(用于存储和组织爬取的数据)。
pip install requests beautifulsoup4 pandas
下载完成后,您需要导入这些库。
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
在导入BeautifulSoup、requests、pandas后,我们需要获取 HTML 内容。本部分的代码将使用 requests 来实现 HTTP 请求。requests 是 Python 中一个功能强大且简单易用的 HTTP 库,常用于发送 HTTP 请求以获取网页内容、调用API或提交数据。我们将主要使用 requests.get 功能。关于 requests 的详细信息,可参考相关技术文档:GitHub - psf/requests: A simple, yet elegant, HTTP library.
在这部分,我们首先将使用 requests.get (url, headers=headers, timeout=10) 发送一个GET请求到指定的URL。其中,url 表示目标网页的网址;headers 用于模拟浏览器;timeout 表示的是超过时间,确保程序不会因为网络延迟无限等待。之后,我们将等待服务器返回响应,实现代码包括 response.text(获取网页的HTML内容)和 response.status_code(HTTP 状态码,用于判断请求是否成功)。
我们在这部分代码中设计了一个错误处理,即 except requests.RequestException as e,用于捕捉网络异常(如连接超时、域名解析失败等)。
def get_html(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
}
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
return response.text
else:
print(f"请求失败,状态码:{response.status_code}")
return None
except requests.RequestException as e:
print(f"请求发生错误:{e}")
return None
在使用 requests 获取 HTML 内容后,我们需要使用 BeautifulSoup 将 HTML 文本解析为可操作的树结构,我们将主要使用 BeautifulSoup 的 find_all 和 find 功能实现。find_all 用于查找所有符合条件的 HTML 标签,并返回一个列表;find 用于查找第一个符合条件的 HTML 标签。
首先,将获取到的 HTML 文档解析成 BeautifulSoup 对象,以便于操作和提取数据。html.parser 是 Python 内置的解析器,适合处理简单的 HTML 页面。如果处理复杂页面,也可使用 lxml 或 html5lib。
soup = BeautifulSoup(html, 'html.parser')
其次,我们将定位电影容器。使用 find_all 来查找 HTML 页面中所有 class = "item" 的 div 标签(这些标签包含电影的标题、评分等信息),返回一个包含所有匹配标签的列表,并将其储存在一个空列表 data 中。
movies = soup.find_all('div', class_='item')
data = []
之后,我们需要遍历每部电影并提取数据,提取我们需要的电影标题、评分、评价人数、电影简介、电影链接,将其存储为字典并添加到列表,并返回提取的数据。在本部分,我们同样需要使用 except AttributeError as e 进行错误处理。
for movie in movies:
try:
title = movie.find('span', class_='title').text
rating = movie.find('span', class_='rating_num').text
comments = movie.find('div', class_='star').find_all('span')[-1].text
link = movie.find('a')['href']
intro = movie.find('span', class_='inq').text if movie.find('span', class_='inq') else "暂无简介"
data.append({
"电影标题": title,
"评分": rating,
"评价人数": comments,
"简介": intro,
"链接": link
})
except AttributeError as e:
print(f"解析电影信息出错:{e}")
continue
return data
该部分的完整代码如下。
def parse_html(html):
soup = BeautifulSoup(html, 'html.parser')
movies = soup.find_all('div', class_='item')
data = []
for movie in movies:
try:
title = movie.find('span', class_='title').text
rating = movie.find('span', class_='rating_num').text
comments = movie.find('div', class_='star').find_all('span')[-1].text
link = movie.find('a')['href']
intro = movie.find('span', class_='inq').text if movie.find('span', class_='inq') else "暂无简介"
data.append({
"电影标题": title,
"评分": rating,
"评价人数": comments,
"简介": intro,
"链接": link
})
except AttributeError as e:
print(f"解析电影信息出错:{e}")
continue
return data
在解析HTML并提取数据后,我们将实现一个完整的爬虫,并将数据保存为 CSV 文件,以便后续更好地处理。
我们将爬取豆瓣数据的主函数名为 scrape_douban_top250。通过观察,我们发现豆瓣电影Top250榜单共有10页。因此采用循环变量 page 和字符串拼接的方式,生成分页URL。调用 get_html 函数通过 HTTP 请求获取网页内容,并调用 parse_html 函数使用 BeautifulSoup 解析 HTML 文档,提取结构化数据,如标题、评分、简介等。
def scrape_douban_top250():
base_url = "https://movie.douban.com/top250"
all_data = [] # 初始化一个空列表,用于存储爬取的电影数据
for page in range(10): # 每页有 25 部电影,共 10 页
url = f"{base_url}?start={page * 25}" # 构造分页 URL
print(f"正在爬取第 {page + 1} 页...")
# 调用 get_html 函数获取 HTML 文本
html = get_html(url)
if html:
# 调用 parse_html 函数解析 HTML,提取电影数据
page_data = parse_html(html)
all_data.extend(page_data) # 将当前页数据添加到总数据列表
print(f"第 {page + 1} 页爬取完成,共获取 {len(page_data)} 条数据")
# 为了避免被封,设置每次请求后暂停 1 秒
time.sleep(1)
return all_data # 返回所有爬取到的电影数据
之后,我们将爬取到的数据需要以便于分析的格式存储下来,使用 pandas 库,将爬取的数据列表转换成 DataFrame,并导出为CSV文件。
def save_to_csv(data, filename='douban_top250.csv'):
# 将数据转换为 pandas DataFrame
df = pd.DataFrame(data)
# 保存为 CSV 文件,指定 UTF-8 编码以支持中文
df.to_csv(filename, index=False, encoding='utf-8-sig')
print(f"数据已保存到 {filename}")
设计并启动主程序,执行爬取函数 scrape_douban_top250,获取所有电影数据,并调用 save_to_csv 将数据保存成CSV文件。在程序结束时,打印“爬取完成”。
if __name__ == "__main__":
print("开始爬取豆瓣电影 Top 250...")
data = scrape_douban_top250()
save_to_csv(data)
print("爬取完成!")
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
# 获取HTML内容的函数
def get_html(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
}
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
return response.text
else:
print(f"请求失败,状态码:{response.status_code}")
return None
except requests.RequestException as e:
print(f"请求发生错误:{e}")
return None
# 解析HTML并提取数据
def parse_html(html):
soup = BeautifulSoup(html, 'html.parser')
movies = soup.find_all('div', class_='item')
data = []
for movie in movies:
try:
title = movie.find('span', class_='title').text
rating = movie.find('span', class_='rating_num').text
comments = movie.find('div', class_='star').find_all('span')[-1].text
link = movie.find('a')['href']
intro = movie.find('span', class_='inq').text if movie.find('span', class_='inq') else "暂无简介"
data.append({
"电影标题": title,
"评分": rating,
"评价人数": comments,
"简介": intro,
"链接": link
})
except AttributeError as e:
print(f"解析电影信息出错:{e}")
continue
return data
# 爬取多页数据
def scrape_douban_top250():
base_url = "https://movie.douban.com/top250"
all_data = []
for page in range(10): # 每页 25 部电影,共 10 页
url = f"{base_url}?start={page * 25}"
print(f"正在爬取第 {page + 1} 页...")
html = get_html(url)
if html:
page_data = parse_html(html)
all_data.extend(page_data)
print(f"第 {page + 1} 页爬取完成,共获取 {len(page_data)} 条数据")
time.sleep(1) # 控制请求频率
return all_data
# 保存数据到CSV文件
def save_to_csv(data, filename='douban_top250.csv'):
df = pd.DataFrame(data)
df.to_csv(filename, index=False, encoding='utf-8-sig')
print(f"数据已保存到 {filename}")
# 主程序
if __name__ == "__main__":
print("开始爬取豆瓣电影 Top 250...")
data = scrape_douban_top250()
save_to_csv(data)
print("爬取完成!")