from bs4 import BeautifulSoup
import re # 正则表表达式文字匹配
import urllib.request, urllib.error # 指定url,获取网页数据
import xlwt
findlink = re.compile(r'a href="(.*?)">') # 电影链接
findImageSrc = re.compile(r'<img.*src="(.*?)"', re.S) # re.S让换行符包含着其中 #图片链接
findTitle = re.compile(r'<span class="title">(.*)</span>') # 标题
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>') # 评分
findJudge = re.compile(r'<span>(\d*)人评价</span>') # 人数
findInq = re.compile(r'<span class="inq">(.*)</span>') # 概况
findBd = re.compile(r'<p class="">(.*?)</p>', re.S) # 相关信息
def main():
# 定义基础URL,用于构造完整的URL来请求数据
baseurl = "https://movie.douban.com/top250?start="
# 调用getdata函数,传入基础URL,获取数据并返回
datalist = getdata(baseurl)
# 打印获取到的数据列表
print(datalist)
# 定义保存路径,将数据保存到movies.xls文件中
savepath = ".\\movies.xls" # 保存路径
# 调用saveData函数,传入获取到的数据列表和保存路径,保存数据
saveData(datalist, savepath)
# 定义函数,用于发送HTTP请求并获取返回的HTML内容
def askURL(url):
# 定义字典,作为HTTP请求的头部信息
head = {
"User-Agent": " Mozilla / 5.0(Linux;Android6.0;Nexus5 Build / MRA58N) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 99.0.4844.51Mobile Safari / 537.36"
}
# 根据给定的URL和头部信息,构造一个HTTP请求对象
request = urllib.request.Request(url, headers=head)
# 初始化一个空字符串,用于存储HTML内容
html = ""
try:
# 使用urllib.request的urlopen函数,发送HTTP请求并获取响应对象
response = urllib.request.urlopen(request)
# 从响应对象中读取HTML内容,并解码为utf-8格式的字符串
html = response.read().decode('utf-8')
# 注释:打印HTML内容(实际代码被注释掉)
# print(html)
except urllib.error.URLError as e:
# 如果发生URL相关的错误,处理异常
if hasattr(e, "code"):
# 打印异常中的错误代码
print(e.code)
if hasattr(e, "reason"):
# 打印异常中的错误原因描述
print(e.reason)
return html # 返回获取到的HTML内容
# 爬取网页
def getdata(baseurl):
# 初始化一个空的数据列表,用于存放解析出的数据
datalist = []
# 从基础URL开始,循环请求10次,每次请求偏移25
for i in range(0, 10):
url = baseurl + str(i * 25) # 构造完整的URL
html = askURL(url) # 发送HTTP请求并获取HTML内容
soup = BeautifulSoup(html, "html.parser") # 使用BeautifulSoup解析HTML内容
# 遍历解析出的每一个'div'标签,类名为"item"
for item in soup.find_all('div', class_="item"):
# 初始化一个空的数据列表,用于存放当前item的数据
data = []
item = str(item) # 将item转换为字符串,以便进行正则表达式匹配
# 寻找链接
link = re.findall(findlink, item)[0] # 使用正则表达式匹配链接
data.append(link) # 将链接添加到数据列表中
# 寻找图片源地址
image = re.findall(findImageSrc, item)[0] # 使用正则表达式匹配图片源地址
data.append(image) # 将图片源地址添加到数据列表中
# 寻找标题
title = re.findall(findTitle, item) # 使用正则表达式匹配标题
if (len(title) == 2): # 如果匹配到两个标题
ctitle = title[0] # 第一个标题
data.append(ctitle) # 将第一个标题添加到数据列表中
otitle = title[1].replace("/", "") # 第二个标题,移除其中的"/"字符
data.append(otitle.strip()) # 将第二个标题添加到数据列表中,并移除首尾的空格
else: # 如果只匹配到一个标题
data.append(title[0]) # 将标题添加到数据列表中
data.append(" ") # 添加一个空格,作为第二个标题的占位符
# 寻找评分
rating = re.findall(findRating, item)[0] # 使用正则表达式匹配评分
data.append(rating) # 将评分添加到数据列表中
# 寻找评价人数
judgeNum = re.findall(findJudge, item)[0] # 使用正则表达式匹配评价人数
data.append(judgeNum) # 将评价人数添加到数据列表中
# 寻找描述或简介
inq = re.findall(findInq, item) # 使用正则表达式匹配描述或简介
if len(inq) != 0: # 如果匹配到了描述或简介
inq = inq[0].replace("。", "") # 移除其中的"。"字符
data.append(inq) # 将描述或简介添加到数据列表中
else: # 如果没匹配到描述或简介
data.append("") # 在数据列表中添加一个空字符串作为占位符
bd = re.findall(findBd, item)[0] # 使用正则表达式匹配导演或主演信息,这里可能存在错误,导演和主演信息不在一起匹配,此处可能需要分别处理导演和主演的信息。
# 并且匹配结果也没有处理双引号的问题。导演和主演的信息可能需要分开处理。
bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd) # 替换HTML中的换行标签为空格字符,这里可能需要考虑HTML转义字符的问题。
# 并且这里只替换了一次,可能存在重复替换的问题。导演和主演的信息可能需要分别处理。
bd = re.sub('/', " ", bd) # 将"/"替换为空格字符,这里可能存在错误,因为"/ "在正则表达式中被错误地转义了
# 3 保存数据
# 定义saveData的函数,接收两个参数:datalist和savepath
def saveData(datalist, savepath):
# 打印"save...",表示开始保存数据
print("save...")
# 创建一个Excel工作簿,设置编码为utf-8,样式压缩为0
book = xlwt.Workbook(encoding="utf-8", style_compression=0)
# 在工作簿中添加一个名为'movies'的工作表,设置cell_overwrite_ok为True,表示允许覆盖单元格内容
sheet = book.add_sheet('movies', cell_overwrite_ok=True)
# 定义一个包含列名的列表
col = ("Movies_link", "Image_link", "Chinese_name", "Foreign_name", "Rating", "Reviews", "概况", "Summary")
# 循环遍历col中的每一个元素,从0到7,将元素写入到工作表的第0行对应列中
for i in range(0, 8):
sheet.write(0, i, col[i])
# 循环遍历datalist中的每一个元素,从0到249
for i in range(0, 250):
# 打印当前处理的条目序号
print("第%d条" % (i + 1))
# 从datalist中获取第i个元素,赋值给data
data = datalist[i]
# 循环遍历data中的每一个元素,从0到7,将元素写入到工作表的第i+1行对应列中
for j in range(0, 8):
sheet.write(i + 1, j, data[j])
# 将工作簿保存到指定的路径下,文件名为savepath
book.save(savepath)
main()
print("爬取完毕!")
项目结构:
- 导入库
- 正则表达式:用于匹配网页中电影信息中的链接、图片标题等
- 主程序:调用get_data和save_data
- HTTP请求函数:ask_URL
- 获取电影数据函数:get_data à 把信息保存data_list中
- 保存数据函数:save_data