简 介: 此系统主要通过爬取豆瓣电影TOP250及其用户短评,并通过Tkinter设计用户操作界面,将数据分析的结果进行展示。
关键词: python, tikinter,gui,requests,爬虫,桌面程序
————————————————
第一次写,先上一张成品图 :
爬取网页:
def getData(baseurl):
datalist = []
for i in range(0, 10):
url = baseurl + str(i * 25)
html = askURL(url) # 保存爬取的网页源码
# 逐一解析数据
soup = BeautifulSoup(html, "html.parser")
for item in soup.find_all('div', class_="item"):
# print(item) # 测试
data = [] # 保存
item = str(item)
# re库正则表达式来查找指定字符串,形成列表
Link = re.findall(findLink, item)[0] # 链接
# print(Link)
data.append(Link)
ImaSrc = re.findall(findImaSrc, item)[0] # 图片链接
# print(ImaSrc)
data.append(ImaSrc)
Title = re.findall(findTitle, item)[0] # 片名:可能只有一个中文名,没有外译名字
if (len(Title) == 2):
cTitle = Title[0] # 添加中文名
# print(cTitle)
data.append(Title)
oTitle = Title[1].replace("/", "") # 外译片名
else:
data.append(Title)
Rating = re.findall(findRating, item)[0] # 评分
data.append(Rating)
Judge = re.findall(findJudge, item)[0] # 评价人数
data.append(Judge)
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] # 相关内容
temp = re.search('[0-9]+.*\/?', Bd).group().split('/')
year, country, category = temp[0], temp[1], temp[2] # 得到年份、地区、类型
data.append(year)
data.append(country)
data.append(category)
datalist.append(data) # 把处理好的一部电影信息放入datalist
return datalist
保存数据:
# 保存数据
def saveData(datalist, savepath):
text.insert(END, "开始保存!!!! \n")
text.update()
book = xlwt.Workbook(encoding="utf-8") # 创建workbook对象
sheet = book.add_sheet('豆瓣电影Top250', cell_overwrite_ok=True) # 创建工作表
# 制作表头
col = ("电影详情链接", "图片链接", "中文名", "评分", "评价数", "概述", "上映年份","制片国家","类型")
for i in range(0, len(col)):
sheet.write(0, i, col[i])
for i in range(0, 250):
# print("第%d条"%(i+1))
data = datalist[i]
for j in range(0, len(col)):
sheet.write(i + 1, j, data[j])
这些是针对豆瓣电影TOP250,即https://movie.douban.com/top250,这个链接页面进行爬取相应字段。
def start_spider(urls,name):
base_url = urls+'comments'
print(base_url) #打印 url
start_url = base_url + '?start=0' #给url 一个初始的链接
number = 1
html = request_get(start_url)
marvelthree = []
while html.status_code == 200:
selector = etree.HTML(html.text)
nextpage = selector.xpath("//div[@id='paginator']/a[@class='next']/@href")
nextpage = nextpage[0]
next_url = base_url + nextpage
# 获取评论
comments = selector.xpath("//div[@class='comment']")
#遍历获取的结果
for each in comments:
marvelthree.append(get_comments(each))
data = pd.DataFrame(marvelthree)
try:
if number == 1:
csv_headers = ['用户', '是否看过', '五星评分', '评论时间', ]
f_name='./电影数据/'+name +".xlsx" #路径
#表头存入到表格中
data.to_excel(f_name, header=csv_headers, index=False, encoding='utf-8')
else:
#将数据存入表格
data.to_excel(f_name, header=False, index=False, encoding='utf-8')
except UnicodeEncodeError:
print("编码错误, 该数据无法写到文件中, 直接忽略该数据")
html = request_get(next_url)
def request_get(url):
'''
使用 Session 能够跨请求保持某些参数。
它也会在同一个 Session 实例发出的所有请求之间保持 cookie
'''
#设置延时3秒
timeout = 3
UserAgent_List = [
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2226.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 4.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2117.157 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1866.237 Safari/537.36",
]
#请求头的header
header = {
'User-agent': random.choice(UserAgent_List),
'Host': 'movie.douban.com',
}
session = requests.Session()
cookie = { #用自己的
}
time.sleep(random.randint(2, 10))
#请求后的页面
response = requests.get(url, headers=header, cookies=cookie, timeout = 3)
if response.status_code != 200:
print(response.status_code)
return response #返回结果页面html
def get_comments(eachComment):
commentlist = []
user = eachComment.xpath("./h3/span[@class='comment-info']/a/text()")[0] # 用户
watched = eachComment.xpath("./h3/span[@class='comment-info']/span[1]/text()")[0] # 是否看过
rating = eachComment.xpath("./h3/span[@class='comment-info']/span[2]/@title") # 五星评分
if len(rating) > 0:
#有的话就拿第一个
rating = rating[0]
comment_time = eachComment.xpath("./h3/span[@class='comment-info']/span[3]/@title") # 评论时间
if len(comment_time) > 0:
# 有的话就拿第一个
comment_time = comment_time[0]
else:
# 有些评论是没有五星评分, 需赋空值
#如果没有评分 那rating 就是时间,将时间给comment_time
comment_time = rating
#置空
rating = ''
commentlist.append(user)
commentlist.append(watched)
commentlist.append(rating)
commentlist.append(comment_time)
return commentlist
普通爬虫就不做过多解释了。
#做个开始爬的方法
def starPinglu():
#给前端打印 评论爬虫开始
text.insert(END, "评论爬虫开始!!!! \n")
text.update() #更新上去
df = pd.read_excel('./豆瓣电影Top 250.xls') #读取 豆瓣电影Top 250.xls
d_l=df['电影详情链接'].head(10).to_list() #取电影详情链接 这列的前十个 并转换成列表
numb=0
#遍历前十电影链接
for i in d_l:
#获取对应电影名
name=qianshi(numb)
#开始爬虫 传进去电影链接 电影名
start_spider(i,name)
numb+=1
做了一个开始爬的方法 后面会有按钮调用
#可视化图表
def pingfen():
df=pd.read_excel('./豆瓣电影Top 250.xls')
d_p=df.groupby("评分").count()
a.clear()
a.plot(d_p)
canvas_spice.draw()
def shangyingnianfen():
df=pd.read_excel('./豆瓣电影Top 250.xls')
df['年'] = df["上映年份"].str[0:4]
a.clear()
d_p=df.groupby("年").count()
a.plot(d_p)
canvas_spice.draw()
评论分布,上映年份的点线图 这里换成柱状图也行的或其他图形
def ui():
global text
label = Label(root, text="事件输出框-----文本显示", bg="yellow")
text = Text(root, width=35, height=5,bg="Cyan")
# 第四行开始按扭,command绑定事件
b_Start_250 = Button(root, text='开始爬豆瓣T250', bg="pink",command=lambda: thread_it(func))
b_Start_shufen=Button(root, text='评分分布图',bg="pink", command=lambda: thread_it(pingfen))
b_Start_shangying = Button(root, text='上映年份', bg="pink", command=lambda: thread_it(shangyingnianfen))
#单个电影的 自己做方法就可以 然后依次添加进来
label2.place(x=350, y=15)
b_Start_pinglu.place(x=550,y=13)
#布局标题
label.place(x=10, y=50)
#布局文本框
text.place(x=10, y=80)
b_Start_250.place(x=10, y=10)
b_Start_shufen.place(x=130, y=10)
b_Start_shangying.place(x=220, y=10)
fig = plt.figure(figsize=(13, 17), dpi=50) # 图像比例
global a
a = fig.add_subplot(211) # 划分区域
global canvas_spice
canvas_spice = FigureCanvasTkAgg(fig, root)
canvas_spice.get_tk_widget().place(x=0, y=120) # 放置位置
很多人在做Tkinter的时候,启动一个耗时较长的方法后,界面就卡死了。这是因为整个程序是单线程的。所以,需要开多线程。如下:
def thread_it(func, *args):
'''将函数打包进线程'''
# 创建
t = threading.Thread(target=func, args=args)
# 守护 !!!
t.setDaemon(True)
# 启动
t.start()
这种方法我是屡试不爽,很有用也很方便。
最后一张展示图:
另:本工作室长期接单,放单。涉及领域有python java 前后端 机器学习 网站 系统 app 小程序等。
需要接单加v备注技术领域:ad2021wyz
需要做单加v备注需要做什么:ad2020wyz