美文网首页
爬虫眼中的“周庄”长什么样?

爬虫眼中的“周庄”长什么样?

作者: 山阴少年 | 来源:发表于2018-09-20 15:04 被阅读30次

      本次爬虫项目将会爬取携程网中关于“周庄古镇”的点评,然后对这些评论进行中文分词及预处理,形成一张关于“周庄古镇”的词云图,得到可视化的分析结果。

    项目介绍

      马上要到中秋啦,正好这几天在公司不太忙,想着中秋假期即将去周庄旅游,于是,笔者心血来潮地想到,能不能利用爬虫做一些关于周庄的分析呢?琢磨许久,笔者终于有了思路,因此,本次爬虫的大致思路是这样的:

    • 获取数据: 利用爬虫爬取携程网中关于周庄的点评
    • 文本预处理:对这些评论进行中文分词以及预处理
    • 可视化分析: 制作词云图并分析

      整个项目的结构如下:

    项目结构

    其中,两个Python文件分别为爬虫文件和文本预处理及制作词云图文件,zhouzhuang.csv为爬取的评论文件,zhouzhuang.txt为结巴分词时添加的词语文件,simsun.ttc为制作词云图时的字体文件(为了能在词云图中正确地显示中文,你需要这个字体文件)。

    爬取携程中的评论

      首先我们需要获取数据,即关于周庄的点评。笔者选取携程网中对“周庄古镇”的点评作为项目的数据集,具体网址为:http://you.ctrip.com/sight/zhouzhuang81/109861-dianping.html 。该网页一共有8285条点评,共分415页展示,每页20条评论,评论有长有短,也有图片,我们只需要评论中的文字部分。如下图所示:

    携程网上关于周庄的评论

      接下来,笔者利用Python爬取这些网页中评论,完整的Python代码(zhouzhuang_comments_scrape.py)如下:

    import requests
    import pandas as pd
    from bs4 import BeautifulSoup
    from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
    
    # 评论列表
    comments = []
    
    # 提取评论,传入参数为网址url
    def get_comment(url):
    
        global comments
    
        try:
            # 发送HTTP请求
            headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 \
                                 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
            r = requests.get(url=url, headers=headers)
    
            # 解析网页,定位到评论部分
            soup = BeautifulSoup(r.text, 'lxml')
            main_content = soup.find_all('div', class_='comment_single')
    
            # 提取评论
            for para in main_content:
                comment = para.find('span', class_='heightbox')
                print(comment.text)
                comments.append(comment.text.replace('&quot', ''))
    
        except Exception as err:
            print(err)
    
    def main():
        # 请求网址(共415个网页)
        urls = ["http://you.ctrip.com/sight/zhouzhuang81/109861-dianping-p%d.html"%x for x in range(1,416)]
        urls[0] = urls[0].replace('-p1', '')
    
        # 利用多线程爬取景点评论
        executor = ThreadPoolExecutor(max_workers=20)  # 可以自己调整max_workers,即线程的个数
        # submit()的参数: 第一个为函数, 之后为该函数的传入参数,允许有多个
        future_tasks = [executor.submit(get_comment, url) for url in urls]
        # 等待所有的线程完成,才进入后续的执行
        wait(future_tasks, return_when=ALL_COMPLETED)
    
        # 创建DataFrame并保存到csv文件
        comments_table = pd.DataFrame({'id': range(1, len(comments)+1),
                                       'comments': comments})
    
        comments_table.to_csv(r"./ZhouZhuang/zhouzhuang.csv", index=False)
    
    main()
    

    在这个爬虫中,我们利用了concurrent.futures这个模块中的多线程来加速爬取评论,同时将这个评论储存在pandas中的DataFrame中,最后将这些评论保存为zhouzhuang.csv文件,便于后续的文本预处理。zhouzhuang.csv文件的内容如下:

    zhouzhuang.csv文件内容(部分)

      事实表明,该网站虽然写着有8285条评论,但csv文件中却只有3020条评论,而且笔者自己也验证了以下,大概200页之后的网站确实也没评论了,难道需要其它操作?Anyway,3千多条评论足够了。

    文本预处理

      在这部分,我们只是讲解文本预处理的操作流程,并不会给出Python代码,Python代码会在后续的“制作词云图”部分一起给出,作为一个完整的Python文件。
      文本预处理的流程如下:

    • 利用Pandas读取评论的csv文件(zhouzhuang.csv);
    • 对该csv文件中的每一条评论,先进行中文分词处理(带有词性标注),然后去掉特殊字符和标点符号,再去掉常用的停用词(stopwords);
    • 对评论中的名次及词性为“非语素字” 的词语进行词频统计。

      我们给出在中文分词过程中用到的用户自己添加的词语,即zhouzhuang.txt中的词语,如下:

    江南水乡
    江南第一水乡
    沈万三
    周庄
    苏州
    昆山
    纸箱王主题创意园区
    纸箱王
    双桥
    沈万三故居
    沈厅
    古戏台
    张厅
    四季周庄
    周庄南湖
    富安桥
    迷楼
    怪楼
    贞丰桥
    逸飞之家
    生命奥秘博物馆
    贞丰文化街
    台湾老街
    沈万三水冢
    太平桥
    全福讲寺
    澄虚道院
    周庄舫
    叶楚伧故居
    牌楼塔影
    爱渡风情小镇
    源丰顺酒作坊
    白蚬湖
    周庄博物馆
    戴宅
    福洪桥
    万三水上财道游
    古镇水巷游
    南湖秋月园
    全福塔
    全福长桥
    蚬江渔唱馆
    蜡工坊名人蜡像馆
    画家村
    大诚堂
    亲亲鱼鱼疗馆
    太史淀
    周庄绿乐园
    大吉祥文化馆
    周庄魔城
    云海塔
    周庄富贵园
    永庆庵
    舟际皮划艇俱乐部
    英伦骑士马术俱乐部
    网咖
    江南第一水乡
    万三蹄髈
    朱元璋
    5A级景区
    北宋
    元祐元年
    万三蹄
    江南六大古镇
    完美
    月圆之夜
    5A级景区
    万三
    平江路
    山塘街
    同里
    万历年间
    万历
    乌镇
    第一水乡
    打call
    5A级旅游景区
    5A景区
    陈逸飞
    

    制作词云图

      接下来就是最后的制作词云图部分了,在这儿,我们可以得到关于“周庄古镇”的评论的可视化结果。
      需要注意的是,你的Python中需要安装wordcloud模块,同时,为了能在词云图中正常地显示中文,需要添加一下中文字体库。具体的制作过程不再详述,笔者这里只给出最简单的词云图绘制。
      完整的Python代码(comments_anlysis.py)如下

    # -*- coding: utf-8 -*-
    import jieba.posseg
    import pandas as pd
    from collections import defaultdict
    import matplotlib.pyplot as plt
    from wordcloud import WordCloud
    
    # 词频统计字典
    dic = defaultdict(int)
    
    # 对每条评论进行分词及预处理
    def cut_word(sentence):
    
        # 去掉句子中的特殊字符及标点符号
        sentence = sentence.replace('&quot', '').replace('\n', '')
        biaodian_list = '~!@#¥%……&*()【】{}:;‘’“”《》,。、? -_,./<>;:\'"!$^()  ヾ?~≈′'
        for biaodian in biaodian_list:
            sentence = sentence.replace(biaodian, '')
    
        # 分词(带词性标注)
        words = jieba.posseg.cut(sentence)
    
        # 常用词
        stop_words = ['的', '我', '你', '他', '她', '它', '我们', '你们', '他们', '她们', '它们', \
                      '这', '这儿', '那', '那儿', '在', '在哪', '这里', '哪里', '那里', '了', '吗','啊', \
                      '是', '不是', '着', '谢谢', '也', '就', '去', '到', '可以', '不', '什么', '会', \
                      '再', '哦', '有', '很', '都', '和', '还是', '还', '感觉', '上', '但', '来',\
                      '一个', '地方', '就是',  '里面', '一次', '一些', '这次', '已经', '又', '个', '这个', \
                      '那个', '要', '但是', '里', '看', '住', '让', '太', '没', '说', '时候',\
                      '小', '大', '还有', '走', '不过', '比较']
    
        # 只统计名词或词性为x的词语
        for word in words:
            # 去掉句子中的常用词
            if word.word not in stop_words:
                # 判断是否为名词
                if 'n' in word.flag or 'x' in word.flag:
                    word = word.word # 取出该名词
                    print(word)
                    dic[word] += 1
    
    def main():
    
        jieba.load_userdict(r'./Zhouzhuang/zhouzhuang.txt')
    
        # 读取评论csv文件并进行分词,预处理,统计词频操作
        df = pd.read_csv(r'./Zhouzhuang/zhouzhuang.csv', encoding='utf-8')
        df['comments'].apply(lambda x: cut_word(x))
    
        # 对词语进行排序
        sort_dict = sorted(dic.items(), key=lambda x: x[1], reverse=True)
        # print(sort_dict)
        wl_space_split = []
        for i in range(40):
            print(sort_dict[i])
            for _ in range(sort_dict[i][1]):
                wl_space_split.append(sort_dict[i][0])
    
        # 产生词云图并显示
        my_wordcloud = WordCloud(font_path=r"./Zhouzhuang/simsun.ttc", background_color='white')\
                                .generate(" ".join(wl_space_split))
    
        plt.imshow(my_wordcloud)
        plt.axis("off")
        plt.show()
    
    main()
    

      最高频的40个词语如下:

    ('周庄', 2375)
    ('古镇', 1187)
    ('人', 1113)
    ('小桥流水', 466)
    ('门票', 456)
    ('江南', 456)
    ('景区', 454)
    ('水乡', 416)
    ('江南水乡', 372)
    ('景点', 358)
    ('人家', 337)
    ('景色', 287)
    ('沈厅', 261)
    ('商业', 252)
    ('中国', 250)
    ('商业化', 244)
    ('特色', 243)
    ('万三蹄', 215)
    ('风景', 205)
    ('建议', 194)
    ('气息', 193)
    ('美', 192)
    ('双桥', 188)
    ('第一水乡', 179)
    ('有点', 178)
    ('小镇', 176)
    ('味道', 172)
    ('苏州', 171)
    ('乌镇', 169)
    ('客栈', 165)
    ('张厅', 161)
    ('导游', 148)
    ('生活', 147)
    ('建筑', 147)
    ('时间', 145)
    ('游玩', 143)
    ('沈万三', 142)
    ('文化', 140)
    ('夜景', 139)
    ('游客', 139)
    

    产生的词云图如下:

    “周庄”词云图

    自己的分析

      嗯,好不容易用自己的方法得到了可视化的结果,即上述的词云图,那么,对笔者的中秋之旅会有什么建议呢?

    1. 周庄是个古镇,江南水乡,小桥流水,风景应该很不错。所以,在旅游的过程中,要欣赏景色,也许夜景也是不错的。
    2. 周庄的很多景点及特色也在词云图中有展示,如沈厅,张厅,双桥,万三蹄等,那么,在旅游的过程中,这些事物是不该错过的。
    3. 也有很多人对商业化提出了看法,也许,中国的古镇商业化确实太严重了,搞得所有的古镇都是一个样子,少了很多趣味。
    4. 至于词云图中为什么没有出现“人”,“美”等词语,这是可以打一个问号的。

    项目总结

      本次爬虫项目,爬取了携程网中关于“周庄古镇”的点评,然后对这些评论进行中文分词及预处理,形成一张关于“周庄古镇”的词云图,得到笔者自己的一些分析结果。当然,我们能做的还有很多,比如对评论中提到的景区进行统计,绘制景点提到频数直方图等。
      所谓爬虫,其意义在于为数据建模提供数据,因此,对于数据分析和建模来说,爬虫只是万里长征的第一步。当然,爬虫也可以做很多有意义的事情,那么,你有哪些有意思的项目呢?欢迎交流哦~

      本次爬虫项目仅作为笔者的练手项目,并不作为商用。如有转载或商用,请及时联系笔者,谢谢~
      提前祝大家中秋节快乐~

    注意:本人现已开通微信公众号: 轻松学会Python爬虫(微信号为:easy_web_scrape), 欢迎大家关注哦~~

    相关文章

      网友评论

          本文标题:爬虫眼中的“周庄”长什么样?

          本文链接:https://www.haomeiwen.com/subject/bgcnnftx.html