一、目的与要求
1、目的
通过实验,掌握爬虫的基本原理和相关知识,并能够运用所学知识进行网页数据的获取和解析。理解爬虫的网页分类:通过实验,了解并能够区分静态网页和动态网页,掌握爬取静态网页和动态网页的方法和技巧。爬取和解析网页的流程:通过实验,掌握爬虫的基本流程,包括发送请求、获取网页源代码、解析网页数据等步骤,能够熟练运用urllib库或requests库获取网页源代码。通过实验掌握Xpath语法使用规则,能够提取网页中的目标数据。数据解析与可视化:掌握使用re、lxml等工具进行数据解析,实现数据的清洗和提取。同时,学会使用wordcloud库和matplotlib库进行数据可视化,以更直观、直观地展示爬取的数据。运用数据处理工具:通过实验,掌握jieba、numpy和pandas等数据处理工具的基本使用方法,能够对爬取的数据进行分词、统计、分析等操作,进一步挖掘数据的价值。
通过完成以上实验目的,将掌握爬虫的基本原理和技术,能够独立进行网页数据的获取和解析,并能够运用数据处理工具进行数据分析和可视化,进一步提高信息处理和应用能力。
- 要求
实现爬取电影信息,和影评信息的需求以及爬取需要重复跳转页面获取城市信息的需求。
具体要求:
(1)爬取字段:电影名、导演、主演、类型、制片国家/地区、语言、上映日期、片长、 综合评分、评价人数;影评用户名、用户评分、评论发布时间、评论正文、有用数量、回应 数量等等。
(2)使用工具:Python、urllib、requests、lxml、selenium、scrapy、pandas、time 等适当选择搭配使用。
(3)解析方式:正则表达式、Xpath、bs4 等。
二、课程设计内容
1、题目和环境
题目:豆瓣电影 Top250《肖申克的救赎》电影影评数据的爬取
语言:Python
环境:Anaconda3+Pycharm或Jupyter Notebook
2、过程与步骤
实现该豆瓣电影 Top250《肖申克的救赎》电影影评数据的爬取所涉及的文件:
- publish_city.csv:用于存储爬虫处理后的数据。
(2)filmreview3.csv:用于存储爬虫处理后的电影影评数据。
(3)豆瓣电影 Top250《肖申克的救赎》电影影评数据的爬取.py:用于数据处理。
(4)豆瓣分析电影 Top250《肖申克的救赎》电影影评数据的爬取.py:用于数据分析。
操作过程与步骤如下:
2.1.爬取数据
(1)该段代码使用了pandas库和selenium库来爬取豆瓣电影的页面数据。首先,其中使用了pandas库来导入了pandas模块。接着,使用了selenium库的webdriver模块来启动Chrome浏览器,并通过browser.get()打开了指定网页。然后,使用了time库的sleep函数来等待2秒,以确保页面加载完全。接下来,使用了selenium库的webdriver模块中的page_source属性获取当前页面的源代码,并将其赋值给变量text。最后,使用了lxml库的etree模块中的HTML方法将text转化成可解析的HTML树,并将其赋值给变量tree。
核心代码如图1所示:
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from lxml import etree
browser=webdriver.Chrome()
browser.get('https://movie.douban.com/subject/1292052/')
sleep(2)
text=browser.page_source
tree=etree.HTML(text)
图1 爬取豆瓣网站数据
(2)使用xpath语句获取肖申克救赎的电影信息。复制网页xpath语句添加text()输出文字,然后使用print输出爬取到的内容。
核心代码如下所示:
# 电影名
movie_name=tree.xpath('//*[@id="content"]/h1/span[1]/text()')
sleep(2)
# 导演
movie_Director=tree.xpath('//*[@id="info"]/span[2]/span[2]/a/text()')
sleep(2)
# 主演
movie_Starring=tree.xpath('//*[@id="info"]/span[3]/span[2]/span/a/text()')
sleep(2)
# 类型
movie_type1=tree.xpath('//*[@id="info"]/span[5]/text()')
movie_type2=tree.xpath('//*[@id="info"]/span[6]/text()')
sleep(2)
#制片国家/地区
movie_country=tree.xpath('//*[@id="info"]/span[7]/following-sibling::text()[1]')
sleep(2)
# #语言
movie_language=tree.xpath('//*[@id="info"]/span[8]/following-sibling::text()[1]')
sleep(2)
# #上映日期
movie_date1=tree.xpath('//*[@id="info"]/span[10]/text()')
movie_date2=tree.xpath('//*[@id="info"]/span[11]/text()')
sleep(2)
#片长
movie_time=tree.xpath('//*[@id="info"]/span[13]/text()')
sleep(2)
#综合评分
overall_score=tree.xpath('//*[@id="interest_sectl"]/div[1]/div[2]/strong/text()')
sleep(2)
#评价人数
number_evaluators=tree.xpath('//*[@id="interest_sectl"]/div[1]/div[2]/div/div[2]/a/span/text()')
sleep(2)
print({'电影名':movie_name,'导演':movie_Director,'主演':movie_Starring,'类型1':movie_type1,
'类型2':movie_type2,'制片国家/地区':movie_country,'语言':movie_language,
'上映日期1':movie_date1,'上映日期2':movie_date2,'片长':movie_time,'综合评分':overall_score,
'评价人数':number_evaluators})
图2 爬取肖申克救赎电影信息
运行结果如图4所示:
图3爬取肖申克救赎电影信息结果
(3)首先,它通过点击找到页面上的评论按钮并点击,然后等待3秒钟。接下来,创建了一个名为 filmreview_info的空DataFrame,用于存储爬取到的评论信息。然后进入一个循环,循环50次。在每次循环中首先获取当前页面的HTML代码,并将其解析成一个树形结构。然后查找评论的相关元素,并提取出影评用户名、用户评分、评论发布时间、评论正文、有用数量和回应数量等信息,并将其存储到filmreview_info中。如果该页是需要跳过的页面,则通过查找下一页按钮并点击进行跳过,并等待3秒钟。最后,它将filmreview_info保存为CSV文件,并关闭浏览器。
核心代码下所示:
#点击影评全部按钮
browser.find_element(By.XPATH, '//*[@id="reviews-wrapper"]/header/h2/span/a').click()
sleep(3)
filmreview_info = pd.DataFrame(columns=['影评用户名', '用户评分', '评论发布时间', '评论正文', '有用数量', '回应数量'])
for j in range(50):
text = browser.page_source
tree = etree.HTML(text)
sleep(3)
a = tree.xpath('//*[@id="content"]/div/div[1]/div[1]/div')
if j == 1 or j == 9 or j == 13 or j == 14 or j == 17 or j == 22 or j == 23 or j == 30 or j == 31 or j == 32 or j == 48 or j == 49:
# 查找下一页按钮并点击
next_page_button = browser.find_element(By.CLASS_NAME, 'next')
next_page_button.click()
sleep(3)
else:
for i in range(len(a)):
# 影评用户名
filmreview_name = tree.xpath('/html/body/div[3]/div[1]/div/div[1]/div[1]/div[' + str(i + 1) + ']/div/header/a[2]/text()')
sleep(2)
# 用户评分
user_rating = tree.xpath(' /html/body/ div[3]/div[1] / div / div[1] / div[1] / div[' + str(i + 1) + '] / div / header / span[1]/@title')
sleep(2)
# 评论发布时间
publish_time = tree.xpath('/html/body/div[3]/div[1]/div/div[1]/div[1]/div[' + str(i + 1) + ']/div/header/span[2]/text()')
sleep(2)
# 评论正文
publish_content = tree.xpath('/html/body/div[3]/div[1]/div/div[1]/div[1]/div[' + str(i + 1) + ']/div/div/div[1]/div/text()[1]')
sleep(2)
# 有用数量
useful_count = tree.xpath('/html/body/div[3]/div[1]/div/div[1]/div[1]/div[' + str(i + 1) + ']/div/div/div[3]/a[1]/span/text()')
sleep(2)
# 回应数量
response_count = tree.xpath(
'/html/body/div[3]/div[1]/div/div[1]/div[1]/div[' + str(i + 1) + ']/div/div/div[3]/a[3]/text()')
sleep(2)
new = pd.DataFrame(
{'影评用户名': filmreview_name, '用户评分': user_rating, '评论发布时间': publish_time, '评论正文': publish_content,
'有用数量': useful_count, '回应数量': response_count})
filmreview_info = filmreview_info.append(new, ignore_index=True)
filmreview_info.to_csv('filmreview3.csv', index=False, encoding='utf-8')
# 查找下一页按钮并点击
next_page_button = browser.find_element(By.CLASS_NAME, 'next')
next_page_button.click()
sleep(3)
a.pop()
browser.quit()
图4 爬取影评数据代码
运行结果如图8所示:
图8 爬取影评数据结果
- 首先找到页面上的评论按钮并点击,然后等待3秒钟。接下来,创建了一个名为city_list_info的空DataFrame,用于存储爬取到的用户城市信息。然后进入一个循环,循环50次。在每次循环中首先获取当前页面的HTML代码,并将其解析成一个树形结构。然后,查找评论的相关元素,并逐个点击用户名名称,进入用户主页。再次获取用户主页的HTML代码,并将其解析成一个新的树形结构。然后提取出用户的城市信息,并将其存储到city_list_info中。接着将city_list_info保存为CSV文件,并返回到上一个页面。最后,查找下一页按钮并点击进行翻页,并等待3秒钟。循环结束后,关闭浏览器。
核心代码如图9,图10所示:
# 点击影评全部按钮
browser.find_element(By.XPATH,'//*[@id="reviews-wrapper"]/header/h2/span/a').click()
sleep(3)
city_list_info = pd.DataFrame(columns=['用户城市'])
for j in range(50):
text = browser.page_source
tree = etree.HTML(text)
sleep(3)
a = tree.xpath('//*[@id="content"]/div/div[1]/div[1]/div')
for i in range(len(a)):
#点击用户名名称
browser.find_element(By.XPATH,'/html/body/div[3]/div[1]/div/div[1]/div[1]/div['+str(i+1)+']/div/header/a[2]').click()
sleep(2)
#进入用户页面
text=browser.page_source
tree=etree.HTML(text)
publish_city=tree.xpath('//*[@id="profile"]/div/div[2]/div[1]/div/a/text()')
sleep(2)
city_list = pd.DataFrame({'用户城市': publish_city})
city_list_info = city_list_info.append(city_list, ignore_index=True)
city_list_info.to_csv('publish_city.csv', index=False, encoding='utf-8')
browser.back()
sleep(3)
# 查找下一页按钮并点击
next_page_button = browser.find_element(By.CLASS_NAME, 'next')
next_page_button.click()
sleep(3)
a.pop()
browser.quit()
图9 爬取用户城市数据代码
运行结果如图11所示:
图11 爬取用户城市数据结果
2.2.数据分析
- 该段代码的功能是读取一个名为"publish_city.csv"的CSV文件,并统计每个城市在该文件中出现的次数。首先,使用pandas库的read_csv函数读取CSV文件数据,并将其保存到变量data中。然后,使用numpy库的unique函数获取data中唯一的城市值和每个城市值的出现次数,并将结果保存到变量unique_values和counts中。接下来,使用循环遍历unique_values和counts,分别将城市和对应的人数打印出来。
核心代码如图12所示:
import jieba
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import wordcloud
# 读取csv文件
data = pd.read_csv('publish_city.csv')
# 获取数组中唯一的值和每种值的出现次数
unique_values, counts = np.unique(data, return_counts=True)
# 打印每种类型数据的个数和个数总和
for city, num in zip(unique_values, counts):
print("城市", city, "的人数为:", num)
图12 数据可视化分析代码
(2)首先,设置了图形的大小和分辨率。然后,使用plt.rc("font",family="SimHei")来设置字体为中文,以便显示中文字符。接着绘制了折线图,并p绘制了折线上的散点。创建了y轴刻度列表。然后使用plt.yticks(y_ticks[::5])设置了y轴刻度的显示,每隔5个刻度显示一个值。使用plt.grid(True, linestyle='--', alpha=0.5)添加了网格线,并设置了线型和透明度。设置了x轴标签,并通过rotation=90使其垂直显示。使用plt.ylabel("人数",fontdict={'size': 16})设置了y轴标签。设置了图形的标题。最后使用plt.show()显示了绘制的图形。
核心代码如图13所示:
plt.figure(figsize=(100, 10), dpi=80) # 设置画布大小和分辨率
plt.rc("font",family="SimHei") # 设置字体为中文
plt.plot(unique_values, counts, c='red') # 绘制折线图
plt.scatter(unique_values, counts, c='red') # 绘制散点图
y_ticks = range(120) # 设置y轴刻度范围
plt.yticks(y_ticks[::5]) # 设置y轴刻度间隔为5
plt.grid(True, linestyle='--', alpha=0.5) # 添加网格线
plt.xlabel("城市", fontdict={'size': 16}) # 设置x轴标签
plt.xticks(rotation=90) # 设置x轴刻度旋转角度为90度
plt.ylabel("人数",fontdict={'size': 16}) # 设置y轴标签
plt.title("评论者的城市分布情况", fontdict={'size': 16}) # 设置图表标题
plt.show() # 显示图表
图13 数据可视化图标代码
运行结果如图14所示:
图14 数据可视化分析图标运行结果
(2)根据图表所获取的数组,把字符串另存一个csv文件,然后对存储的内容进行分词,创建一个字典用来存储数据,然后统计词频,使用循环遍历,然后输出显示词云,关闭坐标抽显示,最后展示词云。
核心代码如图15所示:
#词云
#使用join函数将data['用户城市']中的元素以分号(';')连接成一个字符串
title=';'.join([ str(c) for c in data['用户城市'].tolist()])
#使用jieba库的lcut函数对字符串进行分词,生成一个列表
gen=jieba.lcut(title)
#创建一个空字典data,用于统计词频
data={}
#遍历分词后的列表gen
for i in gen:
if len(str(i))>1:
# 如果大于1,则将该词作为字典data的key,value为该词的词频
# 如果该词已经在字典data中,则将其value加1
data[i] = data.get(i,0)+1
# 创建词云对象
cloud=wordcloud.WordCloud(background_color='white',font_path='C:/Windows/Fonts/方正粗黑宋简体.ttf')
# 生成云图,从给定的频率数据中
cloud.generate_from_frequencies(frequencies=data)
plt.figure(dpi=120) #分辨率
# 显示词云图
plt.imshow(cloud,interpolation='bilinear')
# 不显示坐标轴
plt.axis('off')
#展示
plt.show()
图15 数据可视化分析词云代码
运行结果如图16所示:
图16数据可视化分析词云代码
可视化分析的结论为:
评论数量最多的前 5 个城市排名为:
北京、上海、四川成都、广东广州、浙江杭州
三、总结
在我的课设实验中,我学习了爬虫的网页分类、爬取和解析网页的流程。为了获取网页的源代码,我使用了requests库。然后,我使用了Xpath语法掌握了其使用规则,通过使用lxml等工具对数据进行解析。使用这几个库爬取了电影的信息,电影影评和城市数据。在数据解析的过程中,我还学习了wordcloud库和matplotlib库来进行可视化处理,绘制了折线图更方便显示统计好的数据信息,还学习了jieba、numpy和pandas库用于数据的处理和分析,制作词云,使用了这几个库。通过这些学习和实践,我能够有效地爬取网页数据,并对其进行分类和解析。同时,我也能够利用各种工具和库对数据进行处理、分析和可视化展示。总的来说,这个课设实验使我对爬虫和数据解析有了更深入的理解,并且熟悉了一些常用的工具和库。