python爬虫--自定义爬取网站数据并进行可视化分析

今天写了一个爬虫,爬取了豆瓣网和腾讯网上一些信息,然后又用python自带的tkinter库制作了一个图形化界面,下面时代码和思路。
**代码下载地址:**https://download.csdn.net/download/weixin_43866709/11049544

思路

 (1)为了用户更好的操作,先用pythonGUI编程设计出一个界面。
(2)编写爬虫代码,以豆瓣网为例,思考自己所需要的数据资源,并以此为基础设计自己的爬虫程序。
(3)分析网页前端代码,找出数据所在的标签,并通过正则表达式或者Xpath匹配出想要的数据。
(4)应用python第三方库Request,伪装成浏览器发送请求,获取豆瓣网页面。
(5)用提前编写好的匹配规则代码匹配出想要爬取的数据,并将这些数据保存起来。
(6)通过jieba分词库对数据进行处理,再通过scipy库对数据进行分析,最后在使用matplotlib,wordcloud库对处理结果进行展示。

设计方案:

1.界面设计:
这个界面使用python自带的tkinter库绘制,考虑到要让用户可以自定义输入想要爬取的网站,还要让用户看到爬取日志以及数据处理结果,使用到该库中的自定义输入框,文本框和画布,自定义输入框用于用户输入网址,文本框用于同步爬取日志,画布用来展示词云图。除此之外,还要添加几个必要的按钮,包括爬虫开始按钮,生成图片按钮,还有退出程序按钮。

具体代码如下:

# 创建空白窗口,作为主载体
 # root = tkinter.Tk()
self.root.title('爬虫工具')
# 窗口的大小,后面的加号是窗口在整个屏幕的位置
self.root.geometry('1068x715+10+10')
# 创建菜单
menubar = tkinter.Menu(self.root)
fmenu = tkinter.Menu(menubar)
# for each in ['新建', '打开', '保存', '另存为', '退出']:
fmenu.add_command(label='新建')
fmenu.add_command(label='打开')
fmenu.add_command(label='保存')
fmenu.add_command(label='另存为')
fmenu.add_command(label='退出', command=self.root.quit, accelerator='(Ctrl+Q)')
rmenu = tkinter.Menu(menubar)
# for each in ['运行爬虫', '生成图片']:
rmenu.add_command(label='运行爬虫', command=self.douban_comments, accelerator='(F11)')
rmenu.add_command(label='生成图片', command=self.make_image, accelerator='(F12)')
amenu = tkinter.Menu(menubar)
for each in ['版权信息', '联系我们']:
    amenu.add_command(label=each)
menubar.add_cascade(label='文件', menu=fmenu)
menubar.add_cascade(label='运行', menu=rmenu)
menubar.add_cascade(label='关于', menu=amenu)

self.root['menu'] = menubar
# 标签控件,窗口中放置文本组件
tkinter.Label(self.root, text='请输入url:', font=("华文行楷", 20), fg='black').grid(row=0, column=0)

# 定位 pack包 place位置 grid是网格式的布局
tkinter.Label(self.root, text='输出结果:', font=("宋体", 20), fg='black').grid(row=1, column=12)
tkinter.Label(self.root, text='爬取日志:', font=("宋体", 20), fg='black').grid(row=2, column=0)
# Entry是可输入文本框
# url_input = tkinter.Entry(self.root, font=("微软雅黑", 15))
# url_input.grid(row=0, column=1)
# 下拉框
# StringVar是Tk库内部定义的字符串变量类型,在这里用于管理部件上面的字符;不过一般用在按钮button上。改变StringVar,按钮上的文字也随之改变。
number = tkinter.StringVar()
url_input = tkinter.ttk.Combobox(self.root, width=26, textvariable=number)
# 设置下拉列表的值
url_input['values'] = ('https://hr.tencent.com', 'https://book.douban.com')
url_input.grid(column=1, row=0)


# tkinter.Label(self.root, text='腾讯网url: https://hr.tencent.com', font=("微软雅黑", 10), fg='black').grid(row=2, column=1)
# tkinter.Label(self.root, text='豆瓣网url: https://book.douban.com', font=("微软雅黑", 10), fg='black').grid(row=1, column=1)
# 文本控件,打印日志
log_text = tkinter.Text(self.root, font=('微软雅黑', 15), width=35, height=20)
# columnspan组件所跨越的列数
log_text.grid(row=4, column=0, rowspan=9, columnspan=10)
# result_text = tkinter.Canvas(self.root, width=45, height=22)
result_text = tkinter.Canvas(self.root, bg='white', width=550, height=600)
result_text.grid(row=2, column=12, rowspan=15, columnspan=10)
# 设置按钮 sticky对齐方式,N S W E
tkinter.button = tkinter.Button(self.root, text='开始', font=("微软雅黑", 15), command=self.douban_comments).grid(row=13, column=0, sticky=tkinter.W)
tkinter.button = tkinter.Button(self.root, text='退出', font=("微软雅黑", 15), command=self.root.quit).grid(row=13, column=10, sticky=tkinter.E)
# 创建滚动条
log_text_scrollbar_y = tkinter.Scrollbar(self.root)
log_text_scrollbar_y.config(command=log_text.yview)
log_text.config(yscrollcommand=log_text_scrollbar_y.set)
log_text_scrollbar_y.grid(row=3, column=10, rowspan=9, sticky='NS')
# 使得窗口一直存在
tkinter.mainloop()

运行效果:
在这里插入图片描述

2.爬取数据

爬虫最主要的处理对象就是URL,它根据URI地址取得所需要的文件内容,然后对它进行进一步的处理。因此,准确地理解URL对理解网络爬虫至关重要。
URL是URI的一个子集。它是Uni form Resource Locator的缩写,译为“统一资源定位符”。通俗地说,URL是Internet.上描述信息资源的字符串,主要用在各种WW客户程序和服务器程序上。采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。URL的格式由三部分组成:
①第一部分是协议(或称为服务方式)。
②第二部分是存有该资源的主机IP地址(有时也包括端口号)。③第三部分是主机资源的具体地址,如目录和文件名等。第一部分和第二部分用“//”符号隔开,第二部分和第三部分用“/”符号隔开。
第一部分和第二部分是不可缺少的,第三部分有时可以省略。
发送请求获取响应文件我们使用的是request库,requests库是一个简洁且简单的HTTP请求的第三方库,它的优点是程序编写过程更接近正常URL访问过程。

具体代码如下:

headers = {'User-Agent': Spider.ua.random}
# proxies = main()
# 豆瓣网top250书籍首页
# url = "https://book.douban.com"
url = url_input.get()
if url == 'https://book.douban.com':
    for i in range(0, 1):
        urls = url + '/top250?start=' + 'str(i*25)'
        html = requests.get(urls, headers=headers).text

3.解析网页(本文使用Xpath,也可使用正则表达式,bs4等)

XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初XPath的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是XPath很快的被开发者采用来当作小型查询语言,XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。路径表达式是从一个XML节点(当前的上下文节点)到另一个节点、或一组节点的书面步骤顺序。这些步骤以“/”字符分开,每一步有三个构成成分:
轴描述(用最直接的方式接近目标节点)
节点测试(用于筛选节点位置和名称)
节点描述(用于筛选节点的属性和子节点特征)
一般情况下,我们使用简写后的语法。虽然完整的轴描述是一种更加贴近人类语言,利用自然语言的单词和语法来书写的描述方式,但是相比之下也更加啰嗦。

具体代码如下:

page = etree.HTML(html)
book_urls_list = page.xpath('//tr[@class="item"]/td/div/a/@href')
book_name_list = page.xpath('//tr[@class="item"]/td/div/a/@title')

4.数据处理
(1)首先将爬取下来的数据存储成json文件,代码如下:

with open('douban.txt', 'a+', encoding='utf-8') as f:
    for s in pattern:
        # print(s, type(s))
        f.write(str(s))

(2)使用jieba库对数据进行分词,在分词时对一些字符串忽略掉,代码如下:

stop_words = set(line.strip() for line in open('stopwords.txt', encoding='utf-8'))
commentlist = []
for subject in comment_subjects:
    if subject.isspace():
        continue
    # segment words line by line
    word_list = pseg.cut(subject)
    for word, flag in word_list:
        if word not in stop_words and flag == 'n':
            commentlist.append(word)

(3)使用科学计算库scipy,2D绘图库matploylib和wordcloud库生成词云图,直观的向用户展示出热门的词汇,代码如下:

d = path.dirname(__file__)
timg_image = imread(path.join(d, "timg.png"))
content = ' '.join(commentlist)
wordcloud = WordCloud(font_path='simhei.ttf', background_color="grey",  mask=timg_image, max_words=40).generate(content)
# Display the generated image:
plt.imshow(wordcloud)
plt.axis("off")
wordcloud.to_file('wordcloud.gif')
# plt.show()
# wordcloud_image = Image.open('wordcloud.gif')
wordcloud_images = tkinter.PhotoImage(file='wordcloud.gif')
result_text.create_image(50, 50, anchor=tkinter.NW, image=wordcloud_images)

源代码

import jieba.posseg as pseg
import matplotlib.pyplot as plt
from os import path
import requests
from scipy.misc import imread
from wordcloud import WordCloud
from bs4 import BeautifulSoup
import time
from lxml import etree
import random
from fake_useragent import UserAgent
import tkinter
from tkinter import ttk
# from PIL import Image



class Spider:
    ua = UserAgent(verify_ssl=False)

    def __init__(self):
        self.root = tkinter.Tk()

    def douban_comments(self):
        headers = {'User-Agent': Spider.ua.random}
        # proxies = main()
        # 豆瓣网top250书籍首页
        # url = "https://book.douban.com"
        url = url_input.get()
        if url == 'https://book.douban.com':
            for i in range(0, 1):
                urls = url + '/top250?start=' + 'str(i*25)'
                html = requests.get(urls, headers=headers).text
                page = etree.HTML(html)
                book_urls_list = page.xpath('//tr[@class="item"]/td/div/a/@href')
                book_name_list = page.xpath('//tr[@class="item"]/td/div/a/@title')
                for book_name in book_name_list:
                    log_msg1 = '匹配到《' + str(book_name) + '》' + '\n'
                    log_text.insert(tkinter.END, log_msg1)
                    log_text.see(tkinter.END)
                    log_text.update()
                print(book_urls_list)
                # 得到每一本书对应的评论url
                for book_urls in book_urls_list:
                    comments_urls = book_urls + 'comments/hot?p='
                    print(comments_urls)
                    # 获取每一本书前一百页的评论url
                    for j in range(1, 2):
                        comments_url = comments_urls + 'str(j)'
                        comments = requests.get(comments_url, headers=headers)
                        # print('开始爬取第{}页评论.'.format(j))
                        log_msg2 = '开始爬取第{}页评论.'.format(j) + '\n'
                        log_text.insert(tkinter.END, log_msg2)
                        log_text.see(tkinter.END)
                        log_text.update()

                        comments_soup = BeautifulSoup(comments.text, 'lxml')
                        pattern = comments_soup.find_all('p', 'comment-content')
                        with open('douban.txt', 'a+', encoding='utf-8') as f:
                            for s in pattern:
                                # print(s, type(s))
                                f.write(str(s))
                        j = j + 1
                        time.sleep(1)
                i = i + 1
                time.sleep(1)
            spi_end = '--------爬取完成--------' + '\n'
            log_text.insert(tkinter.END, spi_end)
            log_text.see(tkinter.END)
            log_text.update()
        elif url == 'https://hr.tencent.com':
            self.tencent_position()
        else:
            self.error_msg()

    @staticmethod
    def tencent_position():
        headers = {'User-Agent': Spider.ua.random}
        url = url_input.get()
        for i in range(0, 20):
            urls = url + '/position.php?&start=' + 'str(i*10)'
            html = requests.get(urls, headers=headers).text
            log_msg2 = '开始爬取第{}页职位.'.format(i) + '\n'
            log_text.insert(tkinter.END, log_msg2)
            log_text.see(tkinter.END)
            log_text.update()
            page = etree.HTML(html)
            for position in page.xpath('//tr[@class="even"]/td[1]/a/text() | //tr[@class="odd"]/td[1]/a/text()'):
                with open('tencent.txt', 'a+', encoding='utf-8') as f:
                    f.write(str(position))
            i = i + 1
            time.sleep(1)
        spi_end = '--------爬取完成--------' + '\n'
        log_text.insert(tkinter.END, spi_end)
        log_text.see(tkinter.END)
        log_text.update()

    @staticmethod
    def error_msg():
        msg = '请先输入正确的url~' + '\n'
        log_text.insert(tkinter.END, msg)
        log_text.see(tkinter.END)
        log_text.update()

    def make_image(self):
        make_image_text = '============================' + '\n' + '正在生成图片...请稍等...' + '\n'
        log_text.insert(tkinter.END, make_image_text)
        log_text.see(tkinter.END)
        log_text.update()
        global wordcloud_images
        url = url_input.get()
        if url == 'https://book.douban.com':
            with open('douban.txt', 'r', encoding='utf-8') as f:
                comment_subjects = f.readlines()
            stop_words = set(line.strip() for line in open('stopwords.txt', encoding='utf-8'))
            commentlist = []
            for subject in comment_subjects:
                if subject.isspace():
                    continue
                # segment words line by line
                word_list = pseg.cut(subject)
                for word, flag in word_list:
                    if word not in stop_words and flag == 'n':
                        commentlist.append(word)
            d = path.dirname(__file__)
            timg_image = imread(path.join(d, "timg.png"))
            content = ' '.join(commentlist)
            wordcloud = ontWordCloud(f_path='simhei.ttf', background_color="grey",  mask=timg_image, max_words=40).generate(content)
            # Display the generated image:
            plt.imshow(wordcloud)
            plt.axis("off")
            wordcloud.to_file('wordcloud.gif')
            # plt.show()
            # wordcloud_image = Image.open('wordcloud.gif')
            wordcloud_images = tkinter.PhotoImage(file='wordcloud.gif')
            result_text.create_image(50, 50, anchor=tkinter.NW, image=wordcloud_images)
        elif url == 'https://hr.tencent.com':
            with open('tencent.txt', 'r', encoding='utf-8') as f:
                comment_subjects = f.readlines()
            stop_words = set(line.strip() for line in open('stopwords.txt', encoding='utf-8'))
            commentlist = []
            for subject in comment_subjects:
                if subject.isspace():
                    continue
                # segment words line by line
                word_list = pseg.cut(subject)
                for word, flag in word_list:
                    if word not in stop_words and flag == 'n':
                        commentlist.append(word)
            d = path.dirname(__file__)
            timg_image = imread(path.join(d, "timg.png"))
            content = ' '.join(commentlist)
            wordcloud = WordCloud(font_path='simhei.ttf', background_color="grey",  mask=timg_image, max_words=40).generate(content)
            # Display the generated image:
            plt.imshow(wordcloud)
            plt.axis("off")
            wordcloud.to_file('wordcloud_tencent.gif')
            # plt.show()
            # wordcloud_image = Image.open('wordcloud_tencent.gif')
            wordcloud_images = tkinter.PhotoImage(file='wordcloud_tencent.gif')
            result_text.create_image(50, 50, anchor=tkinter.NW, image=wordcloud_images)
        else:
            self.error_msg()

    def main(self):
        global url_input, log_text, result_text
        # 创建空白窗口,作为主载体
        # root = tkinter.Tk()
        self.root.title('爬虫工具')
        # 窗口的大小,后面的加号是窗口在整个屏幕的位置
        self.root.geometry('1068x715+10+10')
        # 创建菜单
        menubar = tkinter.Menu(self.root)
        fmenu = tkinter.Menu(menubar)
        # for each in ['新建', '打开', '保存', '另存为', '退出']:
        fmenu.add_command(label='新建')
        fmenu.add_command(label='打开')
        fmenu.add_command(label='保存')
        fmenu.add_command(label='另存为')
        fmenu.add_command(label='退出', command=self.root.quit, accelerator='(Ctrl+Q)')
        rmenu = tkinter.Menu(menubar)
        # for each in ['运行爬虫', '生成图片']:
        rmenu.add_command(label='运行爬虫', command=self.douban_comments, accelerator='(F11)')
        rmenu.add_command(label='生成图片', command=self.make_image, accelerator='(F12)')
        amenu = tkinter.Menu(menubar)
        for each in ['版权信息', '联系我们']:
            amenu.add_command(label=each)
        menubar.add_cascade(label='文件', menu=fmenu)
        menubar.add_cascade(label='运行', menu=rmenu)
        menubar.add_cascade(label='关于', menu=amenu)

        self.root['menu'] = menubar
        # 标签控件,窗口中放置文本组件
        tkinter.Label(self.root, text='请输入url:', font=("华文行楷", 20), fg='black').grid(row=0, column=0)

        # 定位 pack包 place位置 grid是网格式的布局
        tkinter.Label(self.root, text='输出结果:', font=("宋体", 20), fg='black').grid(row=1, column=12)
        tkinter.Label(self.root, text='爬取日志:', font=("宋体", 20), fg='black').grid(row=2, column=0)
        # Entry是可输入文本框
        # url_input = tkinter.Entry(self.root, font=("微软雅黑", 15))
        # url_input.grid(row=0, column=1)
        # 下拉框
        # StringVar是Tk库内部定义的字符串变量类型,在这里用于管理部件上面的字符;不过一般用在按钮button上。改变StringVar,按钮上的文字也随之改变。
        number = tkinter.StringVar()
        url_input = tkinter.ttk.Combobox(self.root, width=26, textvariable=number)
        # 设置下拉列表的值
        url_input['values'] = ('https://hr.tencent.com', 'https://book.douban.com')
        url_input.grid(column=1, row=0)


        # tkinter.Label(self.root, text='腾讯网url: https://hr.tencent.com', font=("微软雅黑", 10), fg='black').grid(row=2, column=1)
        # tkinter.Label(self.root, text='豆瓣网url: https://book.douban.com', font=("微软雅黑", 10), fg='black').grid(row=1, column=1)
        # 文本控件,打印日志
        log_text = tkinter.Text(self.root, font=('微软雅黑', 15), width=35, height=20)
        # columnspan组件所跨越的列数
        log_text.grid(row=4, column=0, rowspan=9, columnspan=10)
        # result_text = tkinter.Canvas(self.root, width=45, height=22)
        result_text = tkinter.Canvas(self.root, bg='white', width=550, height=600)
        result_text.grid(row=2, column=12, rowspan=15, columnspan=10)
        # 设置按钮 sticky对齐方式,N S W E
        tkinter.button = tkinter.Button(self.root, text='开始', font=("微软雅黑", 15), command=self.douban_comments).grid(row=13, column=0, sticky=tkinter.W)
        tkinter.button = tkinter.Button(self.root, text='退出', font=("微软雅黑", 15), command=self.root.quit).grid(row=13, column=10, sticky=tkinter.E)
        # 创建滚动条
        log_text_scrollbar_y = tkinter.Scrollbar(self.root)
        log_text_scrollbar_y.config(command=log_text.yview)
        log_text.config(yscrollcommand=log_text_scrollbar_y.set)
        log_text_scrollbar_y.grid(row=3, column=10, rowspan=9, sticky='NS')
        # 使得窗口一直存在
        tkinter.mainloop()


if __name__ == "__main__":
    spider = Spider()
    spider.main()

运行效果

在这里插入图片描述

  • 35
    点赞
  • 335
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
### 回答1: Python爬虫可以通过网络爬虫技术获取网页数据,然后使用数据可视化工具将数据可视化数据可视化可以帮助我们更好地理解和分析数据,从而更好地做出决策。Python爬虫数据可视化数据科学中非常重要的两个领域,它们可以帮助我们更好地理解和利用数据。 ### 回答2: Python爬虫是一种能够通过编写代码自动从互联网上获取信息的工具。使用Python编写的爬虫程序可以模拟浏览器进行网页数据的抓取,而网页数据可视化是将抓取到的数据以图表、图像等形式展示出来,便于用户直观地理解和分析数据爬虫首先需要选择合适的库,常用的有BeautifulSoup、Scrapy等。BeautifulSoup是一个用于分析HTML和XML文档的Python库,它可以方便地从网页中提取出你感兴趣的数据。Scrapy是一个功能强大的Web爬虫框架,它可以自定义爬取策略、并发爬取等。 编写爬虫程序时,首先需要通过指定URL来请求网页数据。使用Python的requests库可以方便地发送HTTP请求,并获取到相应的网页内容。通过解析网页内容,可以找到所需的数据,并将其存储到本地文件或数据库中。 数据可视化则需要借助一些数据可视化库,如Matplotlib、Seaborn、Plotly等。这些库提供了丰富的绘图函数,可以根据数据的不同特点选择合适的图表类型。例如,使用Matplotlib可以绘制折线图、散点图、柱状图等,Seaborn则专注于统计图形的绘制,Plotly可以创建交互式可视化图表等。 在爬取数据进行可视化后,可以通过图表直观地展示出数据的趋势、相对大小等特征。这样的可视化结果可以为决策提供依据,帮助用户更好地理解和分析数据。 综上所述,Python爬虫数据可视化是两个互相关联的领域。Python编写的爬虫程序可以获取网页数据,而使用数据可视化技术可以将抓取到的数据以图形化形式展示出来,使数据更加易于理解和分析。 ### 回答3: Python爬虫是一种用于自动化从互联网上获取数据的工具。它利用Python编程语言的强大库和模块,如requests、BeautifulSoup和Selenium等,可以方便地爬取网页上的数据。 首先,我们需要使用requests库发送HTTP请求获取网页的HTML代码。通过分析HTML结构和标签,我们可以使用BeautifulSoup库提取感兴趣的数据,如标题、内容、链接等。此外,如果网页是通过JavaScript动态生成的,我们可以使用Selenium库模拟浏览器行为来获取完整的数据。 获取到数据后,可以进行进一步的处理和清洗,如去除HTML标签、转换数据类型等。然后,我们可以使用Python中的各种库(如pandas、matplotlib和seaborn)来对数据进行可视化分析。 在数据可视化方面,pandas库可以帮助我们进行数据整理和处理,如对数据进行排序、过滤、聚合等。matplotlib和seaborn库则提供了各种绘图函数,如折线图、柱状图、散点图、饼图等,可以将数据以直观的图形展示出来。 除了基本的统计图表,我们还可以使用地图库(如folium、basemap)将数据在地图上展示,或者使用词云库(如wordcloud)将文本数据可视化为漂亮的词云图。 总结起来,通过Python爬虫和相关的数据处理和可视化库,我们可以方便地获取网页上的数据,并将其以各种丰富的形式进行可视化呈现。这不仅可以帮助我们更好地理解和分析数据,还可以用于数据报告、数据仪表盘和数据故事等各种应用中。
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值