基于豆瓣电影TOP250网站的网络爬虫及其拓展项目

环境:Windows10 +Python3.9+anaconda3
一、 项目功能
① 实现简单的用户交互界面
② 从豆瓣电影top250网站上爬取top250电影的相关信息
③ 从豆瓣电影top250网站截取到每一部电影对应的电影编号
④ 通过用户输入的电影排行返回电影相关信息并通过其对应编号进入电影对应的短评界面,爬取前10页的评论内容,删除一些无关紧要词汇后生成词云图。
⑤ 在源代码目录下储存了top250电影信息、爬取电影的影片和生成的词云图。

二、 项目实现
① 爬取豆瓣top250电影的相关信息
通过翻不同豆瓣top250电影页面找规律发现网址遵循第i页的url链接是https://movie.douban.com/top250?start=25*(i-1)&filter=,再通过xpath取出标签属性为info的节点,对节点内容进行获取和截取,将每一部影片的影片名称,评分,上映日期,上映国家,影片类型,评分,评论,人数信息内容写入到本地的txt文件中去。
② 从豆瓣电影top250网站截取到每一部电影对应的电影编号
为了截取网页html代码里的内容,我使用了另外一种方法对html代码进行处理,我使用BeautifulSoup对代码进行标签分析,然后用find_all方法找到所有此标签的内容,然后在此标签中继续寻找符合网址超链接的特殊属性的内容,对他们进行截取从而获得影片编号。
③ 根据用户输入电影排行的爬取电影信息并根据其短评生成词云
根据用户输入,首先判断是否在电影排行范围内,如果是则找到对应的电影编号,爬取对应页面的短评保存到影评txt文件中,并在搜索结果框中显示“爬取短评成功!”,如果用户输入的电影编号不在电影排行范围内,则在搜索结果框中显示“爬取短评失败!爬取短评失败!\n请输入电影排行1~250!”。在爬取完网站前10页的短评并储存在本地后,调用我定义的调用getwordcloud函数,首先剔除一些无关紧要的词语,然后使用结巴分词,再调用wordcloud库,定义wordcloud函数背景颜色,字体,词云数等参数,最后调用调用库中的generate函数生成文本的词云图生成,将生成的词云图展示并保存在本地。
④ GUI交互界面
我选择使用tkinter库,构建了一个MY_GUI类进行GUI界面的设定,我设置了几个窗口的位置,实现了展示全部电影内容的展示和搜索函数的定义。用户可以在右侧的框中看到top250每一部电影的爬取信息,用户可以通过拖动滑块进行上下移动。同时,用户可以搜索电影排行获得电影的相关信息和词云图。

三、 代码截图
① 爬取豆瓣top250电影的相关信息
在这里插入图片描述

② 从豆瓣电影top250网站截取到每一部电影对应的电影编号
在这里插入图片描述

③ 获取用户输入电影排行对应的电影短评网址
在这里插入图片描述

④ 简单的交互界面
在这里插入图片描述

⑤ 爬取电影短评内容
在这里插入图片描述

⑥ 主函数
在这里插入图片描述

四、 项目结果展示

在这里插入图片描述

在这里插入图片描述

五、 困难与解决
① 爬取页面信息
搜索得到豆瓣top250电影首页的网址: https://movie.douban.com/top250。而第二页的网址是:https://movie.douban.com/top250?start=25&filter=,第三页的网址是https://movie.douban.com/top250?start=50&filter=,第四页的网址是https://movie.douban.com/top250?start=75&filter=,因此发现除第一页外,第i页的网址遵循https://movie.douban.com/top250?start=25*(i-1)&filter=,因此我们可以通过这个规律用for循环去遍历每一页的内容。
为了获取我们所需内容的在html中的位置,我们在所需内容处点击右键选择检查打开所需内容的html代码。通过阅读网页代码可以发现,它的内容是多层结构的,每个内容都在一个标签名下的,我们所需的内容在标签属性为info的下,所以我们伪装成浏览器通过urlib向网页发送请求抓取当前页面的html源代码,然后对代码进行html.fromstring 处理,再通过xpath取出标签属性为info的节点,对节点内容进行获取和截取,写入到本地的txt文件中去,最后成功爬取到了top250电影的信息。
② 获取电影编号
在爬取为豆瓣top250电影页面中,不同电影的标签为‘a’的内容里储存着网址的改电影网址的超链接,爬取这个超链接,它们的形式都如https://movie.douban.com/subject/1292052/ ,而这部电影对应的编号为1292052,截取该超链接部分的内容可以实现对电影编号的获取。在代码中,我截取网页html代码里的内容后使用BeautifulSoup对代码进行标签分析,然后用find_all方法找到‘a’标签的内容,然后在此标签中继续寻找符合网址超链接的特殊属性的内容,最终对超链接进行截取对他们进行截取从而获得影片编号。
③ 爬取短评内容
为了爬取短评页面的内容,我伪装成浏览器对该短评页面进行访问,就像爬取豆瓣top250
电影一样,我通过urlib向网页发送请求抓取当前页面的html源代码,然后用req.read().decode对内容进行解码后再用BeautifulSoup对代码进行标签分析,截取每一条评论的内容,将评论都加入列表后储存在本地。
④ 展示搜索内容并生成词云
用户输入搜索内容后,我首先判断内容是否是1250的数字,如果是的话则在爬取电影信息的txt文件中进行数字匹配,匹配到该排行后在电影查询结果框内输出该电影的内容直到储存电影信息末尾的分隔符为止,同时在电影查询结果框内弹出结果"爬取短评成功!\n词云图已保存在本地!\n\n"。如果用户输入的内容不是1250的数字,则在电影查询结果框捏弹出结果"爬取短评失败!\n请输入电影排行1~250!\n\n",提醒用户重新输入信息。
⑤ GUI界面生成
在设计GUI界面时,我设计了三个文本框和一个按钮,分别储存影片信息,用户输入信息和查询结果信息,按钮则是判断用户进行搜索。我首先定义了初始化函数对GUI界面进行初始,我设置了窗口名,窗口初始化在屏幕上的位置,各个标签和按钮的位置还有设定了滑块功能。为了使窗口初始化在屏幕的中央,我用tkinter自带的winfo_screenwidth()和winfo_screenheight()函数获取屏幕的信息从而将窗口初始化在屏幕的中央。为了将第一步爬取的250部电影的信息添加进文本框中,我定义了个showtext函数读取了本地爬取的文本内容添加进文本框框中实现了文本内容的展示。我在主函数搜索内容框在完成搜索后会一直保持
⑥ 维持窗口运行
在主函数处调用mainloop()保持窗口循环使得窗口在每次输入后保持运行状态。
六、完整代码

# -*-coding:utf-8-*-
import urllib.request
from bs4 import BeautifulSoup
from wordcloud import WordCloud
import matplotlib.pyplot as plt
import jieba
import requests 
import urllib.request
import re
from lxml import html
from tkinter import *

l1=[]
def getinf(num):
    #l储存每一页中每一个电影页面对应的编号,如https://movie.douban.com/subject/1292052/,它对应的编号为1292052
    l=[]
    #记录电影的序号
    k = 1
    headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
    }
    with open("top250.txt", "w",encoding='utf-8') as f:
        for i in range(num): 
            url = 'https://movie.douban.com/top250?start={}&filter='.format(i*25) 
            con = requests.get(url,headers=headers).content
            #使用BeautifulSoup进行标签分析
            soup = BeautifulSoup(con, 'html.parser')
            sel = html.fromstring(con) 
            #使用find_all方法找到所有此标签的内容,然后在此标签中继续寻找符合网址超链接的特殊属性的内容,对他们进行截取获得影片编号
            for t in soup.find_all('a'):
                str = t['href']
                if(str[0:33]=="https://movie.douban.com/subject/"):
                    l.append(str[33:len(str)-1])
                    
        # 每个影片相关的信息在属性为info的div标签里,取出每个影片的节点 
            for i in sel.xpath('//div[@class="info"]'): 
            # 影片名称 
                title = i.xpath('div[@class="hd"]/a/span[@class="title"]/text()')[0]
            #影片有关信息:导演演员信息, 上映日期,制片,国家,影片类型,评分,评论人数 
                info = i.xpath('div[@class="bd"]/p[1]/text()') 
                date = info[1].replace(" ", "").replace("\n", "").split("/")[0] 
                rate = i.xpath('//span[@class="rating_num"]/text()')[0] 
                comCount = i.xpath('//div[@class="star"]/span[4]/text()')[0]  
                country = info[1].replace(" ", "").replace("\n", "").split("/")[1] 
                actor = info[0].replace(" ", "").replace("\n", "") 
            #在文件中写入影片名称,评分,上映日期,上映国家,影片类型,评分,评论人数信息
                f.write("TOP%s\n影片名称:%s\n评分:%s %s\n上映日期:%s\n上映国家:%s\n%s\n" % (k, title, rate, comCount, date, country, actor)) 
                f.write("==========================\n")
            #更新电影的序号
                k += 1   
    return l


 
    return content
#将影片编号转化为数字串
def getnum(a,l):
    return int(l[a-1])


#获取url页面并对HTML页面进行解析
def getHtml(url):
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'}
    req = urllib.request.Request(url,headers=headers)
    req = urllib.request.urlopen(req)
    content = req.read().decode('utf-8')
    return content


def getComment(url):
    html = getHtml(url)
    soupComment = BeautifulSoup(html, 'html.parser')
    comments = soupComment.findAll('span', 'short')
    onePageComments = []
    for comment in comments:
        onePageComments.append(comment.getText()+'\n')
    return onePageComments
 
 
# 生成词云
def getwordcloud(filename):
    wuguan=['就',"电影","和","有","一部","部","被","吧","还是","这","不","你","我","在","但","是","能","不能","也","们"]
    text = open("影评.txt", encoding='utf-8', errors='ignore').read()
    for wd in wuguan:
        text = text.replace(wd,"")
    # 结巴分词
    wordlist = jieba.cut(text, cut_all=True)
    wl = " ".join(wordlist)
    wc = WordCloud(
        background_color="white",
        max_words=2000,
        font_path='C:\Windows\Fonts\simfang.ttf',
        height=1200,
        width=1600,
        max_font_size=200,
        random_state=50,
        stopwords=["而","都","很","了","的", "这个", "一个", "没有", "不是", " ", "就是"]
    )
    myword = wc.generate(wl)  # 生成词云
    # 生成词云
    plt.imshow(myword)
    plt.axis("off")
    plt.show()
    wc.to_file('词云图.png')  # 把词云保存下

#一个简单的GUI界面
class MY_GUI():
    def __init__(self,init_window_name):
        self.init_window_name = init_window_name


    #设置窗口
    def set_init_window(self):
        self.init_window_name.title("豆瓣top250电影爬虫   by: fei")      #窗口名
        width = 1068
        heigh = 681
        screenwidth = self.init_window_name.winfo_screenwidth()
        screenheight = self.init_window_name.winfo_screenheight()
        self.init_window_name.geometry('1068x681'+str(screenwidth)+str(screenheight))                        
        #设置标签位置和信息
        self.init_data_label = Label(self.init_window_name, text="输入影片排行(1~250)")
        self.init_data_label.grid(row=0, column=0)
        self.result_data_label = Label(self.init_window_name, text="影片信息")
        self.result_data_label.grid(row=0, column=12)
        self.log_label = Label(self.init_window_name, text="影片查询结果")
        self.log_label.grid(row=12, column=0)
        #文本框
        self.init_data_Text = Text(self.init_window_name, width=67, height=3)  
        self.init_data_Text.grid(row=1, column=0, rowspan=10, columnspan=10)
        self.result_data_Text = Text(self.init_window_name, width=70, height=49)  
        self.showtext()
        self.result_data_Text.grid(row=1, column=12, rowspan=15, columnspan=10)
        self.log_data_Text = Text(self.init_window_name, width=66, height=50) 
        self.log_data_Text.grid(row=13, column=0, columnspan=10)
        #按钮
        self.str_trans_to_md5_button = Button(self.init_window_name, text="搜索", bg="lightblue", width=10,command=self.search_function)  
        self.str_trans_to_md5_button.grid(row=6, column=11)
        #设置滑动块
        self.result_data_scrollbar_y = Scrollbar(self.init_window_name)  
        self.result_data_scrollbar_y.config(command=self.result_data_Text.yview)  
        self.result_data_Text.config(yscrollcommand=self.result_data_scrollbar_y.set)
        self.result_data_scrollbar_y.grid(row=1, column=23, rowspan=15, sticky='NS')


    #功能函数
    def search_function(self):
        msg=''
        src = self.init_data_Text.get(1.0,END)
        num=int(src)
        if num >= 1 and num <= 250:
            st = 'TOP'+str(src)
            f= open("top250.txt","r",encoding='utf-8')
            flag=0
            text=f.readlines()
            for i in text:
                if i == st:
                    flag=1
                if i =='==========================\n':
                    flag=0
                if flag :
                    msg+=i
            self.log_data_Text.insert(END,msg)
            f2 = open('影评.txt', 'w', encoding='utf-8') 
            code=str(getnum(num,l1))
            url1='https://movie.douban.com/subject/'+ code +'/comments?start=' 
            for page in range(10):  # 豆瓣爬取多页评论需要验证。
                url = url1 + str(20*page) + '&limit=20&sort=new_score&status=P'
                print('正在爬取第%s页的评论:' % (page+1))
                for i in getComment(url):
                    f2.write(i)
            print('\n')
            getwordcloud('word_py')
            self.log_data_Text.insert(END,"爬取短评成功!\n词云图已保存在本地!\n\n")
        else:
            self.log_data_Text.insert(END,"爬取短评失败!\n请输入电影排行1~250!\n\n")

            
    def showtext(self):
        f= open("top250.txt","r",encoding='utf-8') 
        text=f.read()
        self.result_data_Text.insert(1.0,text)
        
            
if __name__ == '__main__':
    l1=getinf(10)
    init_window = Tk()              
    obj = MY_GUI(init_window)
    obj.set_init_window()
    #保持窗口运行
    init_window.mainloop()  

七、参考资料
1.https://blog.csdn.net/xing851483876/article/details/80578998
2.https://blog.csdn.net/qq_41251963/article/details/81605331

这是本人第一篇csdn博客,如有错误大家见谅,欢迎指出,谢谢!

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值