精华内容
下载资源
问答
  • 网络爬虫介绍及数据采集

    千次阅读 2015-11-10 19:27:24
    收索系统包括三模块:数据采集模块、页面清洗模块、数据库模块 Heritrix和Nutch,二者均为开源框架(网络爬虫技术框架),,Heritrix是SourceForge的开源产品,Nutch为Apache的一个子项目, 它们都称作网络...
    收索系统包括三大模块:数据采集模块、页面清洗模块、数据库模块

    Heritrix和Nutch,二者均为开源框架(网络爬虫技术框架),,Heritrix是SourceForge的开源产品,Nutch为Apache的一个子项目,
    它们都称作网络爬虫/蜘蛛(Web Crawler),他们实现的原理基本一致,深度遍历网站的资源,将这些资源抓取到本地,
    使用方法都是分析网站的每一个有效的URI,并提交Http请求,从而获得相应结果,并生成本地文件及相应的日志
    信息器。

    Heritrix是一个“archival crawler”-用来获取完整的、精确的、站点内容的深度复制,包括图像以及其他非文本内容
    抓取并存储相关内容。对内容来者不拒,不对页面进行内容上的修改,重新爬行对相同的URL不针对先前的进行替换。爬虫
    Web用户界面启动、监控、调整、允许弹性的定义要获取的URL

    二者的差异:
    Nutch只获取并保存可索引的内容,Heritrixze则是超单全收,力求保存页面全貌。
    Nutch可以修剪内容或者对内容格式进行转换
    Nutch保存内容为数据集库优化格式便于以后索引,刷新替换旧的内容。而Heritrix是添加(追加)新的内容
    Nutch从命令运行、控制。Heritrix有web控制管理界面
    Nutch的定制能力不够强,不过现在已经有了一定改进。Heritrix可控制的参数更多


    抓取策略有两种:


    1、深度优先的抓取策略


    2.广度(宽度)优先的抓取策略


    网络爬虫抓取步骤(流程):


    1.初始化根(入口)URL


    2.判断是否满足URL抓取终止条件(如果URL队列当中的元素为空,或者抓取到了指定数量),如果满足,退出抓取程序,如果不满足,进行3


    3.取出最新的URL(URL出列)


    4.将此URL对应的网页通过一个网页下载器下载到本地


    5.抽取此网页满足条件的URL,并添加到URL队列当中,返回第2步





    展开全文
  • 人的一特性就是喜欢拖延,看了不少时间管理的教材,道理我都懂,可就是不想动。最终,还是因为买了新键盘,就特别想敲敲它,果真是个喜新厌旧的女人,哈哈,不贫了。在开学之前,我计划把学校提供的人工智能方向的...
  • Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警AI和NLP应用等。前文分享了疫情相关新闻数据爬取,并进行中文分词处理文本...

    思来想去,虽然很忙,但还是挤时间针对这次肺炎疫情写个Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警及AI和NLP应用等。希望该系列线上远程教学对您有所帮助,也希望早点战胜病毒,武汉加油、湖北加油、全国加油。待到疫情结束樱花盛开,这座英雄的城市等你们来。

    首先说声抱歉,最近一直忙着学习安全知识,其他系列文章更新较慢,已经有一些人催更了。言归正传,前文分享了疫情相关新闻数据爬取,并进行中文分词处理及文本聚类、LDA主题模型分析。这篇文章将抓取微博话题及评论信息,采用SnowNLP进行简单的情感分析及文本挖掘,包括随时间的情感分布。希望这篇基础性文章对您有所帮助,也非常感谢参考文献中老师的分享,一起加油,战胜疫情!如果您有想学习的知识或建议,可以给作者留言~

    在这里插入图片描述

    在这里插入图片描述

    代码下载地址:https://github.com/eastmountyxz/Wuhan-data-analysis
    CSDN下载地址:https://download.csdn.net/download/Eastmount/12239638

    同时推荐前面作者另外五个Python系列文章。从2014年开始,作者主要写了三个Python系列文章,分别是基础知识、网络爬虫和数据分析。2018年陆续增加了Python图像识别和Python人工智能专栏。

    在这里插入图片描述

    前文阅读:
    [Pyhon疫情大数据分析] 一.腾讯实时数据爬取、Matplotlib和Seaborn可视化分析全国各地区、某省各城市、新增趋势
    [Pyhon疫情大数据分析] 二.PyEcharts绘制全国各地区、某省各城市疫情地图及可视化分析
    [Pyhon疫情大数据分析] 三.新闻信息抓取及词云可视化、文本聚类和LDA主题模型文本挖掘



    一.微博话题数据抓取

    该部分内容参考及修改我的学生兼朋友“杨友”的文章,也推荐博友们阅读他的博客,给予支持。作为老师,最开心的事就是看到学生成长和收获。他的博客地址:python爬虫爬取微博之战疫情用户评论及详情

    微博网址: https://m.weibo.cn/


    1.爬虫解析

    第一步,进入微博审查元素,定位评论对应节点,后续抓取评论信息。
    进入微博后,点击《战疫情》主题下,并随便选择一个动态进行分析,我就选择了“央视新闻网”的一条动态“https://m.weibo.cn/detail/4471652190688865”进行分析。

    在这里插入图片描述

    我们刚打开该话题的时候,它显示的是187条评论,但是在审查时可以看到文章中的20个div,并且每个div中装载一条评论,每个页面原始就只能显示20条评论。

    在这里插入图片描述

    当我们把鼠标不断向下滑动的过程中,网页元素中的div也不断随评论的增加而增加,当活动到底部时,所有评论都加载出来了。初步判断该网页属于ajax加载类型,所以先就不要考虑用requests请求服务器了。


    第二步,获取Ajax加载的动态链接数据,通过发布id定位每条话题。
    这些数据都是通过Ajax动态加载的,点击到《战疫情》主题,发现它的URL并没有变化,具体浏览几篇文章后发现,它的的部分URL都是统一的,文章链接 = ‘https://m.weibo.cn/detail/’+发布时的id,可以通过刚找到的 id 在浏览器中拼接试试。

    在这里插入图片描述

    比如下图所示的微博内容。比如:https://m.weibo.cn/detail/4472846740547511

    在这里插入图片描述


    第三步,下拉网页动态刷新数据,发现获取多个page的规律。
    接下来是获取它下一个加载数据的通道,同样是通过抓包的方式获取,不断的下拉网页,加载出其他的Ajax数据传输通道,再进行对比。可以很明显的看出,它的当前链接就只是带上了 “&page=当前数字” 的标签,并且每次加载出18篇动态文章。

    在这里插入图片描述

    查看元素信息如下图所示,每个page显示18个微博话题。

    在这里插入图片描述

    第四步,调用json.loads()函数或在线网站解析Json数据。
    拿到的数据是json格式,再提取信息前需要把str文本转化为json数据,进行查找,可以使用json库查看它的结构 ,也可以在线json解析查看它的结构,更推荐在线解析,方法结构比较清晰。

    在线解析后的结果,简单的给它打上标签,每一个等级为一块,一级包括二级和三级,二级包括三级… 然后通过前面的标签进行迭代输出,索引出来。在线网站:https://www.json.cn/

    在这里插入图片描述


    第五步,获取每条微博的ID值。
    调用方法如下,然后把拿到的id加在https://m.weibo.cn/detail/ 的后面就可以访问具体的文章了。

    import requests
    api_url = 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059'
    reponse = requests.get(api_url)
    for json in reponse.json()['data']['statuses']:
        comment_ID = json['id']
        print (comment_ID)
    

    在这里插入图片描述

    此时提取所有链接代码如下:

    import requests,time
    from fake_useragent import UserAgent
    
    comment_urls = []
    def get_title_id():
        '''爬取战疫情首页的每个主题的ID'''
        for page in range(1,3):# 这是控制ajax通道的量
            headers = {
                "User-Agent" : UserAgent().chrome #chrome浏览器随机代理
            }
            time.sleep(2)
            # 该链接通过抓包获得
            api_url = 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059&page=' + str(page)
            print (api_url)
            rep = requests.get(url=api_url, headers=headers)
            for json in rep.json()['data']['statuses']:
                comment_url = 'https://m.weibo.cn/detail/' + json['id']
                print (comment_url)
                comment_urls.append(comment_url)
    get_title_id()
    

    输出结果如下:

    https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059&page=1
    https://m.weibo.cn/detail/4472725286834498
    https://m.weibo.cn/detail/4472896510211624
    https://m.weibo.cn/detail/4472846892243445
    https://m.weibo.cn/detail/4472901455185821
    https://m.weibo.cn/detail/4472856669039437
    https://m.weibo.cn/detail/4472897055545751
    https://m.weibo.cn/detail/4472891342667233
    https://m.weibo.cn/detail/4472879381479272
    https://m.weibo.cn/detail/4472889565122923
    https://m.weibo.cn/detail/4472884950738226
    https://m.weibo.cn/detail/4472883461527008
    https://m.weibo.cn/detail/4472904014106917
    ......
    

    第六步,调用requests ajax 爬取更多信息。
    现在需要获取更多的信息,如用户id、性别之类的,这不是selenium可以完成的操作了,还得使用ajax的方式获取json数据,提取详细的信息。这里有个字段是max_id, 我们需要在上一个json文件底部找到该值。

    目标:话题链接、话题内容、楼主ID、楼主昵称、楼主性别、发布日期、发布时间、转发量、评论量、点赞量、评论者ID、评论者昵称、评论者性别、评论日期、评论时间、评论内容

    • 第一个通道

    在这里插入图片描述

    • 现在可以预测下一个max_id
      成功的通过上一个通道拿到了下一个通道的max_id,现在就可以使用ajax加载数据了。
      在这里插入图片描述


    2.爬虫完整代码

    # -*- coding: utf-8 -*-
    import requests,random,re
    import time
    import os
    import csv
    import sys
    import json
    import importlib
    from fake_useragent import UserAgent
    from lxml import etree
    
    importlib.reload(sys)
    startTime = time.time() #记录起始时间
    
    #--------------------------------------------文件存储-----------------------------------------------------
    path = os.getcwd() + "/weiboComments.csv"
    csvfile = open(path, 'a', newline='', encoding = 'utf-8-sig')
    writer = csv.writer(csvfile)
    #csv头部
    writer.writerow(('话题链接','话题内容','楼主ID', '楼主昵称', '楼主性别','发布日期',
                     '发布时间', '转发量','评论量','点赞量', '评论者ID', '评论者昵称',
                     '评论者性别', '评论日期', '评论时间','评论内容')) 
    
    #设置heades
    headers = {
        'Cookie': '_T_WM=22822641575; H5_wentry=H5; backURL=https%3A%2F%2Fm.weibo.cn%2F; ALF=1584226439; MLOGIN=1; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9W5RJaVYrb.BEuOvUQ8Ca2OO5JpX5K-hUgL.FoqESh-7eKzpShM2dJLoIp7LxKML1KBLBKnLxKqL1hnLBoMceoBfeh2EeKBN; SCF=AnRSOFp6QbWzfH1BqL4HB8my8eWNC5C33KhDq4Ko43RUIzs6rjJC49kIvz5_RcOJV2pVAQKvK2UbAd1Uh6j0pyo.; SUB=_2A25zQaQBDeRhGeBM71cR8SzNzzuIHXVQzcxJrDV6PUJbktAKLXD-kW1NRPYJXhsrLRnku_WvhsXi81eY0FM2oTtt; SUHB=0mxU9Kb_Ce6s6S; SSOLoginState=1581634641; WEIBOCN_FROM=1110106030; XSRF-TOKEN=dc7c27; M_WEIBOCN_PARAMS=oid%3D4471980021481431%26luicode%3D20000061%26lfid%3D4471980021481431%26uicode%3D20000061%26fid%3D4471980021481431',
        'Referer': 'https://m.weibo.cn/detail/4312409864846621',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest'
    }
    
    #-----------------------------------爬取战疫情首页的每个主题的ID------------------------------------------
    comments_ID = []
    def get_title_id():
        for page in range(1,21):  #每个页面大约有18个话题
            headers = {
                "User-Agent" : UserAgent().chrome #chrome浏览器随机代理
            }
            time.sleep(1)
            #该链接通过抓包获得
            api_url = 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059&page=' + str(page)
            print(api_url)
            rep = requests.get(url=api_url, headers=headers)
            #获取ID值并写入列表comment_ID中
            for json in rep.json()['data']['statuses']:
                comment_ID = json['id'] 
                comments_ID.append(comment_ID)
    
    #-----------------------------------爬取战疫情每个主题的详情页面------------------------------------------         
    def spider_title(comment_ID):
        try:
            article_url = 'https://m.weibo.cn/detail/'+ comment_ID
            print ("article_url = ", article_url)
            html_text = requests.get(url=article_url, headers=headers).text
            #话题内容
            find_title = re.findall('.*?"text": "(.*?)",.*?', html_text)[0]
            title_text = re.sub('<(S*?)[^>]*>.*?|<.*? />', '', find_title) #正则匹配掉html标签
            print ("title_text = ", title_text)
            #楼主ID
            title_user_id = re.findall('.*?"id": (.*?),.*?', html_text)[1]
            print ("title_user_id = ", title_user_id)
            #楼主昵称
            title_user_NicName = re.findall('.*?"screen_name": "(.*?)",.*?', html_text)[0]
            print ("title_user_NicName = ", title_user_NicName)
            #楼主性别
            title_user_gender = re.findall('.*?"gender": "(.*?)",.*?', html_text)[0]
            print ("title_user_gender = ", title_user_gender)
            #发布时间
            created_title_time = re.findall('.*?"created_at": "(.*?)".*?', html_text)[0].split(' ')
            #日期
            if 'Mar' in created_title_time:
                title_created_YMD = "{}/{}/{}".format(created_title_time[-1], '03', created_title_time[2])
            elif 'Feb' in created_title_time:
                title_created_YMD = "{}/{}/{}".format(created_title_time[-1], '02', created_title_time[2])
            elif 'Jan' in created_title_time:
                title_created_YMD = "{}/{}/{}".format(created_title_time[-1], '01', created_title_time[2])
            else:
                print ('该时间不在疫情范围内,估计数据有误!URL = ')
                pass
            print ("title_created_YMD = ", title_created_YMD)
            #发布时间
            add_title_time = created_title_time[3]
            print ("add_title_time = ", add_title_time)
            #转发量
            reposts_count = re.findall('.*?"reposts_count": (.*?),.*?', html_text)[0]
            print ("reposts_count = ", reposts_count)
            #评论量
            comments_count = re.findall('.*?"comments_count": (.*?),.*?', html_text)[0]
            print ("comments_count = ", comments_count)
            #点赞量
            attitudes_count = re.findall('.*?"attitudes_count": (.*?),.*?', html_text)[0]
            print ("attitudes_count = ", attitudes_count)   
            comment_count = int(int(comments_count) / 20) #每个ajax一次加载20条数据
            position1 = (article_url, title_text, title_user_id, title_user_NicName,title_user_gender, title_created_YMD, add_title_time, reposts_count, comments_count, attitudes_count, " ", " ", " ", " "," ", " ")
            #写入数据
            writer.writerow((position1))
            return comment_count
        except:
            pass
    
    
    #-------------------------------------------------抓取评论信息---------------------------------------------------
    #comment_ID话题编号
    def get_page(comment_ID, max_id, id_type):
        params = {
            'max_id': max_id,
            'max_id_type': id_type
        }
        url = ' https://m.weibo.cn/comments/hotflow?id={}&mid={}&max_id'.format(comment_ID, comment_ID)
        try:
            r = requests.get(url, params=params, headers=headers)
            if r.status_code == 200:
                return r.json()
        except requests.ConnectionError as e:
            print('error', e.args)
            pass
    
    #-------------------------------------------------抓取评论item最大值---------------------------------------------------
    def parse_page(jsondata):
        if jsondata:
            items = jsondata.get('data')
            item_max_id = {}
            item_max_id['max_id'] = items['max_id']
            item_max_id['max_id_type'] = items['max_id_type']
            return item_max_id
    
    #-------------------------------------------------抓取评论信息---------------------------------------------------
    def write_csv(jsondata):
        for json in jsondata['data']['data']:
            #用户ID
            user_id = json['user']['id']
            # 用户昵称
            user_name = json['user']['screen_name']
            # 用户性别,m表示男性,表示女性
            user_gender = json['user']['gender']
            #获取评论
            comments_text = json['text']
            comment_text = re.sub('<(S*?)[^>]*>.*?|<.*? />', '', comments_text) #正则匹配掉html标签
            # 评论时间
            created_times = json['created_at'].split(' ')
            if 'Feb' in created_times:
                created_YMD = "{}/{}/{}".format(created_times[-1], '02', created_times[2])
            elif 'Jan' in created_times:
                created_YMD = "{}/{}/{}".format(created_times[-1], '01', created_times[2])
            else:
                print ('该时间不在疫情范围内,估计数据有误!')
                pass
            created_time = created_times[3] #评论时间时分秒
            #if len(comment_text) != 0:
            position2 = (" ", " ", " ", " "," ", " ", " ", " ", " ", " ", user_id, user_name, user_gender, created_YMD, created_time, comment_text)
            writer.writerow((position2))#写入数据
            #print (user_id, user_name, user_gender, created_YMD, created_time)    
    
    
    #-------------------------------------------------主函数---------------------------------------------------
    def main():
        count_title = len(comments_ID)
        for count, comment_ID in enumerate(comments_ID):
            print ("正在爬取第%s个话题,一共找到个%s话题需要爬取"%(count+1, count_title))
            #maxPage获取返回的最大评论数量
            maxPage = spider_title(comment_ID)
            print ('maxPage = ', maxPage)
            m_id = 0
            id_type = 0
            if maxPage != 0: #小于20条评论的不需要循环
                try:
                    #用评论数量控制循环
                    for page in range(0, maxPage):
                        #自定义函数-抓取网页评论信息
                        jsondata = get_page(comment_ID, m_id, id_type)
                        
                        #自定义函数-写入CSV文件
                        write_csv(jsondata)
                        
                        #自定义函数-获取评论item最大值
                        results = parse_page(jsondata)
                        time.sleep(1)
                        m_id = results['max_id']
                        id_type = results['max_id_type']              
                except:
                    pass
            print ("--------------------------分隔符---------------------------")
        csvfile.close() 
        
    if __name__ == '__main__':
        
        #获取话题ID
        get_title_id()
        
        #主函数操作
        main()
        
        #计算使用时间
        endTime = time.time()
        useTime = (endTime-startTime) / 60
        print("该次所获的信息一共使用%s分钟"%useTime)
    

    保存数据截图如下图所示:

    在这里插入图片描述

    下图时抓取的话题页面网址,每个页面包括18个话题。

    在这里插入图片描述

    接着抓取每个话题的内容,如下所示:

    正在爬取第1个话题,一共找到个361话题需要爬取
    article_url =  https://m.weibo.cn/detail/4484575189181757
    title_text =#国家卫健委回应健康码互通互认#】国家卫生健康委规划司司长毛群安:目前全国低风险县域已占98%,各省份正在按照统一的数据格式标准和内容要求,加快向全国一体化平台汇聚本地区防疫健康信息的目录。截至目前,#全国绝大多数健康码可实现一码通行#。 人民日报的微博视频 
    title_user_id =  2803301701
    title_user_NicName =  人民日报
    title_user_gender =  m
    该时间不在疫情范围内,估计数据有误!URL = 
    maxPage =  None
    --------------------------分隔符---------------------------
    正在爬取第2个话题,一共找到个361话题需要爬取
    article_url =  https://m.weibo.cn/detail/4484288164243251
    title_text =  法国网友自称自己成了长发公主,度过了居家隔离后的第三天.....#全球疫情##法国疫情# 法国囧事的微博视频 
    title_user_id =  2981906842
    title_user_NicName =  法国囧事
    title_user_gender =  m
    该时间不在疫情范围内,估计数据有误!URL = 
    maxPage =  None
    --------------------------分隔符---------------------------
    正在爬取第3个话题,一共找到个361话题需要爬取
    article_url =  https://m.weibo.cn/detail/4484492666507389
    title_text =  #全球疫情# #意大利疫情# #意大利# “罗马还有其他四处的药店都遭到了抢劫。我们遭受到的是持械抢劫。“这是一位罗马药店药剂师的陈述。她说,在当前疫情的危机情况下,我们处在两难困境之中:受到抢劫和疾病的双重威胁。疫情之下,意大利口罩告急,价格飙高。市民认为是药店不卖,而真实情况是药店真的没有,而供货商又抬高了价格。药店处在两难境地。这位药剂师道出了自己的苦衷,冒着危险还在工作,与医护人员一样,都是奋斗在一线做出牺牲的人。呼吁民众理解,也请求大家的帮助。 Nita大呵呵的微博视频
    title_user_id =  6476189426
    title_user_NicName =  Nita大呵呵
    title_user_gender =  f
    该时间不在疫情范围内,估计数据有误!URL = 
    maxPage =  None
    

    最终抓取360个疫情话题内容。

    在这里插入图片描述


    注意:该爬虫评论写入功能需要改进下,且只能抓取当天的“战疫情”话题及评论,如果想针对某个突发事件进行一段时间的分析,建议每天定时运行该程序,从而形成所需的数据集。也可以根据需求修改为热点话题的抓取,增加搜索功能等。

    作者前文:
    [python爬虫] Selenium爬取新浪微博内容及用户信息
    [Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)
    [Python爬虫] Selenium爬取新浪微博移动端热点话题及评论 (下)



    二.微博话题词云分析

    首先,我们对文本进行简单的词云可视化分析。

    1.基本用法

    词云分析主要包括两种方法:

    • 调用WordCloud扩展包画图(兼容性极强,之前介绍过)
    • 调用PyEcharts中的WordCloud子包画图(本文推荐新方法)

    PyEcharts绘制词云的基础代码如下:

    # coding=utf-8
    from pyecharts import options as opts
    from pyecharts.charts import WordCloud
    from pyecharts.globals import SymbolType
    
    # 数据
    words = [
        ('背包问题', 10000),
        ('大整数', 6181),
        ('Karatsuba乘法算法', 4386),
        ('穷举搜索', 4055),
        ('傅里叶变换', 2467),
        ('状态树遍历', 2244),
        ('剪枝', 1868),
        ('Gale-shapley', 1484),
        ('最大匹配与匈牙利算法', 1112),
        ('线索模型', 865),
        ('关键路径算法', 847),
        ('最小二乘法曲线拟合', 582),
        ('二分逼近法', 555),
        ('牛顿迭代法', 550),
        ('Bresenham算法', 462),
        ('粒子群优化', 366),
        ('Dijkstra', 360),
        ('A*算法', 282),
        ('负极大极搜索算法', 273),
        ('估值函数', 265)
    ]
    
    # 渲染图
    def wordcloud_base() -> WordCloud:
        c = (
            WordCloud()
            .add("", words, word_size_range=[20, 100], shape='diamond')  # SymbolType.ROUND_RECT
            .set_global_opts(title_opts=opts.TitleOpts(title='WordCloud词云'))
        )
        return c
    
    # 生成图
    wordcloud_base().render('词云图.html')
    

    输出结果如下图所示,出现词频越高显示越大。

    在这里插入图片描述

    核心代码为:
    add(name, attr, value, shape=“circle”, word_gap=20, word_size_range=None, rotate_step=45)

    • name -> str: 图例名称
    • attr -> list: 属性名称
    • value -> list: 属性所对应的值
    • shape -> list: 词云图轮廓,有’circle’, ‘cardioid’, ‘diamond’, ‘triangleforward’, ‘triangle’, ‘pentagon’, ‘star’可选
    • word_gap -> int: 单词间隔,默认为20
    • word_size_range -> list: 单词字体大小范围,默认为[12,60]
    • rotate_step -> int: 旋转单词角度,默认为45


    2.疫情词云

    接着我们将3月20日疫情内容复制至“data.txt”文本,经过中文分词后显示前1000个高频词的词云。代码如下:

    # coding=utf-8
    import jieba
    import re
    import time
    from collections import Counter
    
    #------------------------------------中文分词------------------------------------
    cut_words = ""
    all_words = ""
    f = open('C-class-fenci.txt', 'w')
    for line in open('C-class.txt', encoding='utf-8'):
        line.strip('\n')
        seg_list = jieba.cut(line,cut_all=False)
        # print(" ".join(seg_list))
        cut_words = (" ".join(seg_list))
        f.write(cut_words)
        all_words += cut_words
    else:
        f.close()
    
    # 输出结果
    all_words = all_words.split()
    print(all_words)
    
    # 词频统计
    c = Counter()
    for x in all_words:
        if len(x)>1 and x != '\r\n':
            c[x] += 1
    
    # 输出词频最高的前10个词
    print('\n词频统计结果:')
    for (k,v) in c.most_common(10):
        print("%s:%d"%(k,v))
    
    # 存储数据
    name = time.strftime("%Y-%m-%d") + "-fc.csv"
    fw = open(name, 'w', encoding='utf-8')
    i = 1
    for (k,v) in c.most_common(len(c)):
        fw.write(str(i)+','+str(k)+','+str(v)+'\n')
        i = i + 1
    else:
        print("Over write file!")
        fw.close()
    
    #------------------------------------词云分析------------------------------------
    from pyecharts import options as opts
    from pyecharts.charts import WordCloud
    from pyecharts.globals import SymbolType
    
    # 生成数据 word = [('A',10), ('B',9), ('C',8)] 列表+Tuple
    words = []
    for (k,v) in c.most_common(1000):
        # print(k, v)
        words.append((k,v))
    
    # 渲染图
    def wordcloud_base() -> WordCloud:
        c = (
            WordCloud()
            .add("", words, word_size_range=[20, 100], shape=SymbolType.ROUND_RECT)
            .set_global_opts(title_opts=opts.TitleOpts(title='全国新型冠状病毒疫情词云图'))
        )
        return c
    
    # 生成图
    wordcloud_base().render('疫情词云图.html')
    

    输出结果如下图所示,仅3月20日的热点话题内容。

    在这里插入图片描述

    在这里插入图片描述



    3.WordCloud

    另一种方法的代码如下:

    # coding=utf-8
    import jieba
    import re
    import sys
    import time
    from collections import Counter
    import matplotlib.pyplot as plt
    from wordcloud import WordCloud
    
    #------------------------------------中文分词------------------------------------
    cut_words = ""
    all_words = ""
    f = open('data-fenci.txt', 'w')
    for line in open('data.txt', encoding='utf-8'):
        line.strip('\n')
        seg_list = jieba.cut(line,cut_all=False)
        # print(" ".join(seg_list))
        cut_words = (" ".join(seg_list))
        f.write(cut_words)
        all_words += cut_words
    else:
        f.close()
    
    # 输出结果
    all_words = all_words.split()
    print(all_words)
    
    # 词频统计
    c = Counter()
    for x in all_words:
        if len(x)>1 and x != '\r\n':
            c[x] += 1
    
    # 输出词频最高的前10个词
    print('\n词频统计结果:')
    for (k,v) in c.most_common(10):
        print("%s:%d"%(k,v))
    
    # 存储数据
    name = time.strftime("%Y-%m-%d") + "-fc.csv"
    fw = open(name, 'w', encoding='utf-8')
    i = 1
    for (k,v) in c.most_common(len(c)):
        fw.write(str(i)+','+str(k)+','+str(v)+'\n')
        i = i + 1
    else:
        print("Over write file!")
        fw.close()
    
    #------------------------------------词云分析------------------------------------
    #打开本体TXT文件
    text = open('data.txt').read()
     
    #结巴分词 cut_all=True 设置为精准模式 
    wordlist = jieba.cut(text, cut_all = False)
     
    #使用空格连接 进行中文分词
    wl_space_split = " ".join(wordlist)
    #print(wl_space_split)
     
    #对分词后的文本生成词云
    my_wordcloud = WordCloud().generate(wl_space_split)
     
    #显示词云图
    plt.imshow(my_wordcloud)
    #是否显示x轴、y轴下标
    plt.axis("off")
    plt.show()
    


    三.SnowNLP情感分析用法

    情感分析的基本流程如下图所示,通常包括:

    • 自定义爬虫抓取文本信息;
    • 使用Jieba工具进行中文分词、词性标注;
    • 定义情感词典提取每行文本的情感词;
    • 通过情感词构建情感矩阵,并计算情感分数;
    • 结果评估,包括将情感分数置于0.5到-0.5之间,并可视化显示。

    在这里插入图片描述

    1.SnowNLP

    SnowNLP是一个常用的Python文本分析库,是受到TextBlob启发而发明的。由于当前自然语言处理库基本都是针对英文的,而中文没有空格分割特征词,Python做中文文本挖掘较难,后续开发了一些针对中文处理的库,例如SnowNLP、Jieba、BosonNLP等。注意SnowNLP处理的是unicode编码,所以使用时请自行decode成unicode。

    Snownlp主要功能包括:

    • 中文分词(算法是Character-Based Generative Model)
    • 词性标注(原理是TnT、3-gram 隐马)
    • 情感分析
    • 文本分类(原理是朴素贝叶斯)
    • 转换拼音、繁体转简体
    • 提取文本关键词(原理是TextRank)
    • 提取摘要(原理是TextRank)、分割句子
    • 文本相似(原理是BM25)

    推荐官网给大家学习。
    安装和其他库一样,使用pip安装即可。

    pip install snownlp
    

    在这里插入图片描述



    2.中文分词

    下面是最简单的实例,使用SnowNLP进行中文分词,同时比较了SnowNLP和Jieba库的分词效果。

    # -*- coding: utf-8 -*-
    from snownlp import SnowNLP
    s1 = SnowNLP(u"这本书质量真不太好!")
    print("SnowNLP:")
    print(" ".join(s1.words))
    
    import jieba
    s2 = jieba.cut(u"这本书质量真不太好!", cut_all=False)
    print("jieba:")
    print(" ".join(s2))
    

    输出结果如下所示:

    总体感觉是SnowNLP分词速度比较慢,准确度较低,比如“不太好”这个词组,但也不影响我们后续的情感分析。


    3.常见功能

    代码如下:

    # -*- coding: utf-8 -*-
    from snownlp import SnowNLP
    s = SnowNLP(u"这本书质量真不太好!")
    
    print(u"\n中文分词:")
    print( " ".join(s.words))
    
    print(u"\n词性标注:")
    print(s.tags)
    for k in s.tags:
        print(k)
    
    print(u"\n情感分数:")
    print(s.sentiments)
    
    print(u"\n转换拼音:")
    print(s.pinyin)
    
    print(u"\n输出前4个关键词:")
    print(s.keywords(4))
    for k in s.keywords(4):
        print(k)
    
    print(u"\n输出关键句子:")
    print(s.summary(1))
    for k in s.summary(1):
        print(k)
    
    print(u"\n输出tf和idf:")
    print(s.tf)
    print(s.idf)
    
    n = SnowNLP(u'「繁體字」「繁體中文」的叫法在臺灣亦很常見。')
    print(u"\n繁简体转换:")
    print(n.han)
    

    s.words 输出分词后的结果,词性标注主要通过 s.tags,s.sentiments 计算情感分数,s.pinyin 转换为拼音,s.keywords(4) 提取4个关键词,s.summary(1) 输出一个关键句子,s.tf 计算TF值(频率),s.idf 计算IDF值(倒文档)。

    输出结果如下所示:

    >>> 
    
    中文分词:
    这 本书 质量 真 不 太 好 !
    
    词性标注:
    [(u'\u8fd9', u'r'), (u'\u672c\u4e66', u'r'), (u'\u8d28\u91cf', u'n'), 
    (u'\u771f', u'd'), (u'\u4e0d', u'd'), (u'\u592a', u'd'), 
    (u'\u597d', u'a'), (u'\uff01', u'w')]
    (u'\u8fd9', u'r')
    (u'\u672c\u4e66', u'r')
    (u'\u8d28\u91cf', u'n')
    (u'\u771f', u'd')
    (u'\u4e0d', u'd')
    (u'\u592a', u'd')
    (u'\u597d', u'a')
    (u'\uff01', u'w')
    
    情感分数:
    0.420002029202
    
    转换拼音:
    [u'zhe', u'ben', u'shu', u'zhi', u'liang', u'zhen', u'bu', u'tai', u'hao', u'\uff01']
    
    输出前4个关键词:
    [u'\u592a', u'\u4e0d', u'\u8d28\u91cf', u'\u771f']
    太
    不
    质量
    真
    
    输出关键句子:
    [u'\u8fd9\u672c\u4e66\u8d28\u91cf\u771f\u4e0d\u592a\u597d']
    这本书质量真不太好
    
    输出tf和idf:
    [{u'\u8fd9': 1}, {u'\u672c': 1}, {u'\u4e66': 1}, 
    {u'\u8d28': 1}, {u'\u91cf': 1}, {u'\u771f': 1}, 
    {u'\u4e0d': 1}, {u'\u592a': 1}, {u'\u597d': 1}, {u'\uff01': 1}]
    {u'\uff01': 1.845826690498331, u'\u4e66': 1.845826690498331, u'\u8d28': 1.845826690498331, 
    u'\u592a': 1.845826690498331, u'\u4e0d': 1.845826690498331, u'\u672c': 1.845826690498331, 
    u'\u91cf': 1.845826690498331, u'\u8fd9': 1.845826690498331, u'\u597d': 1.845826690498331, u'\u771f': 1.845826690498331}
    
    繁简体转换:
    「繁体字」「繁体中文」的叫法在台湾亦很常见。
    >>> 
    

    同样可以进行文本相似度计算,代码参考下图所示:


    4.情感分析

    SnowNLP情感分析也是基于情感词典实现的,其简单的将文本分为两类,积极和消极,返回值为情绪的概率,越接近1为积极,接近0为消极。其原理参考zhiyong_will大神和邓旭东老师的文章,也强烈推荐大家学习。地址:
    情感分析——深入snownlp原理和实践
    自然语言处理库之snowNLP

    下面简单给出一个情感分析的例子:

    # -*- coding: utf-8 -*-
    from snownlp import SnowNLP
    s1 = SnowNLP(u"我今天很开心")
    print(u"s1情感分数:")
    print(s1.sentiments)
    
    s2 = SnowNLP(u"我今天很沮丧")
    print(u"s2情感分数:")
    print(s2.sentiments)
    
    s3 = SnowNLP(u"大傻瓜,你脾气真差,动不动就打人")
    print(u"s3情感分数:")
    print(s3.sentiments)
    

    输出结果如下所示,当负面情感特征词越多,比如“傻瓜”、“差”、“打人”等,分数就会很低,同样当正免情感词多分数就高。

    s1情感分数:
    0.84204018979
    s2情感分数:
    0.648537121839
    s3情感分数:
    0.0533215596706
    

    而在真实项目中,通常需要根据实际的数据重新训练情感分析的模型,导入正面样本和负面样本,再训练新模型。

    • sentiment.train(’./neg.txt’, ‘./pos.txt’)
    • sentiment.save(‘sentiment.marshal’)


    四.SnowNLP微博情感分析实例

    下面的代码是对爬取的疫情话题进行情感分析。本文将抓取的356条(其中4条仅图片)微博疫情话题信息复制至TXT文件中 ,每一行为一条话题,再对其进行中文分词处理。注意,这里仅仅获取序号1-356的情感分数,而其他情感分析可以进行时间对比、主题对比等,其方法和此篇文章类似,希望读者学会举一反三。

    在这里插入图片描述


    1.情感各分数段出现频率

    首先统计各情感分数段出现的评率并绘制对应的柱状图,代码如下:

    # -*- coding: utf-8 -*-
    from snownlp import SnowNLP
    import codecs
    import os
    
    source = open("data.txt","r", encoding='utf-8')
    line = source.readlines()
    sentimentslist = []
    for i in line:
        s = SnowNLP(i)
        print(s.sentiments)
        sentimentslist.append(s.sentiments)
    
    import matplotlib.pyplot as plt
    import numpy as np
    plt.hist(sentimentslist, bins = np.arange(0, 1, 0.01), facecolor = 'g')
    plt.xlabel('Sentiments Probability')
    plt.ylabel('Quantity')
    plt.title('Analysis of Sentiments')
    plt.show()
    

    输出结果如下图所示,可以看到

    对应的分数如下:

    >>>
    4.440892098500626e-16
    0.49055395607520824
    0.9999999999972635
    0.9999998677093149
    0.9979627586368516
    0.9999999990959509
    0.9999830199233769
    0.9998699310812647
    0.9999954477924106
    ...
    

    2.情感波动分析

    接下来分析每条评论的波动情况,代码如下所示:

    # -*- coding: utf-8 -*-
    from snownlp import SnowNLP
    import codecs
    import os
    
    source = open("data.txt","r", encoding='utf-8')
    line = source.readlines()
    sentimentslist = []
    for i in line:
        s = SnowNLP(i)
        print(s.sentiments)
        sentimentslist.append(s.sentiments)
    
    import matplotlib.pyplot as plt
    import numpy as np
    plt.plot(np.arange(0, 356, 1), sentimentslist, 'k-')
    plt.xlabel('Number')
    plt.ylabel('Sentiment')
    plt.title('Analysis of Sentiments')
    plt.show()
    

    输出结果如下所示,呈现一条曲线,因为抓取的评论基本都是好评,所以分数基本接近于1.0,而真实分析过程中存在好评、中评和差评,曲线更加规律。

    同时,在做情感分析的时候,我看到很多论文都是将情感区间从[0, 1.0]转换为[-0.5, 0.5],这样的曲线更加好看,位于0以上的是积极评论,反之消极评论。修改代码如下:

    # -*- coding: utf-8 -*-
    from snownlp import SnowNLP
    import codecs
    import os
    
    #获取情感分数
    source = open("data.txt","r", encoding='utf-8')
    line = source.readlines()
    sentimentslist = []
    for i in line:
        s = SnowNLP(i)
        print(s.sentiments)
        sentimentslist.append(s.sentiments)
    
    #区间转换为[-0.5, 0.5]
    result = []
    i = 0
    while i<len(sentimentslist):
        result.append(sentimentslist[i]-0.5)
        i = i + 1
    
    #可视化画图
    import matplotlib.pyplot as plt
    import numpy as np
    plt.plot(np.arange(0, 356, 1), result, 'k-')
    plt.xlabel('Number')
    plt.ylabel('Sentiment')
    plt.title('Analysis of Sentiments')
    plt.show()
    

    绘制图形如下所示:



    3.情感时间分布

    最后补充随时间分布的情感分数相关建议,读者可能也发现抓取的博客存在重复、时间不均衡等现象。微博数据还是非常不好抓取,数据卡住了很多人,也请读者深入分析下。

    (1) 情感分析通常需要和评论时间结合起来,并进行舆情预测等,建议读者尝试将时间结合。比如王树义老师的文章《基于情感分类的竞争企业新闻文本主题挖掘》。

    (2) 情感分析也是可以进行评价的,我们前面抓取的分为5星评分,假设0-0.2位一星,0.2-0.4位二星,0.4-0.6为三星,0.6-0.8为四星,0.8-1.0为五星,这样我们可以计算它的准确率,召回率,F值,从而评论我的算法好坏。

    (3) 作者还有很多情感分析结合幂率分布的知识,因为需要写文章,这里暂时不进行分享,但是这篇基础文章对初学者仍然有一定的帮助。

    (4) BosonNLP也是一个比较不错的情感分析包,建议感兴趣的读者学习,它提供了相关的词典,如下:https://bosonnlp.com/dev/resource。

    (5) 读者如果不太擅长写代码,可以尝试使用情感分析系统。http://ictclas.nlpir.org/nlpir/


    五.总结

    写到这里,第四篇疫情分析的文章就讲解完毕,希望对您有所帮助,尤其是想写文本挖掘论文的读者。后续还会分享舆情分析、威胁情报溯源、知识图谱、预测预警及AI和NLP应用等。如果文章对您有所帮助,将是我写作的最大动力。作者将源代码上传至github,大家可以直接下载。你们的支持就是我撰写的最大动力,加油~

    同时,向钟院士致敬,向一线工作者致敬。侠之大者,为国为民。咱们中国人一生的最高追求,为天地立心,为生民立命,为往圣继绝学,为万世开太平。以一人之力系万民康乐,以一身犯险保大业安全。他们真是做到了,武汉加油,中国加油!

    在这里插入图片描述

    (By:Eastmount 2020-03-21 中午12点于贵阳 http://blog.csdn.net/eastmount/)



    参考文献:
    [1] [python数据挖掘课程] 十三.WordCloud词云配置过程及词频分析 - Eastmount
    [2] python爬虫爬取微博之战疫情用户评论及详情
    [3] [python爬虫] Selenium爬取新浪微博内容及用户信息
    [4] [Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)
    [5] [Python爬虫] Selenium爬取新浪微博移动端热点话题及评论 (下)
    [6] 用pyecharts绘制词云WordCloud - pennyyangpei
    [7] 情感分析——深入snownlp原理和实践
    [8] 自然语言处理库之snowNLP
    [9] 王树义老师的文章《基于情感分类的竞争企业新闻文本主题挖掘》

    展开全文
  • 原博文链接:...分析网站 开始写爬虫程序taobaopy 文件 创建一个爬虫文件taobaopy 文件 添加需要使用的存储容器对象items

    原博文链接:http://www.aobosir.com/blog/2016/12/26/python3-large-web-crawler-taobao-com-import-to-MySQL-database/


    开发环境

    • Python第三方库:lxml、Twisted、pywin32、scrapy
    • Python 版本:python-3.5.0-amd64
    • PyCharm软件版本:pycharm-professional-2016.1.4
    • 电脑系统:Windows 10 64位

    如果你还没有搭建好开发环境,请到这篇博客


    本篇博文的重点内容:

    • 有一些数据,在源码上找不到的,这个时候需要使用 — 抓包。
    • Python调用MySQL数据库

    本爬虫项目的目的是:某个关键字在淘宝上搜索到的所有商品,获取所有商品的: 商品名字、商品链接、商品价格、商品的评论。


    开始实战

    创建一个爬虫项目

    scrapy startproject thirdDemo

    Alt text

    设置防反爬机制(settings.py 文件)

    请参考这篇博客:给 Scrapy 爬虫项目设置为防反爬

    分析网站

    • 分析网页界面
    • 分析网址结构
    • 分析网页源代码

    1 . 分析网页界面:

    我们在淘宝网的搜索栏里面搜索关键字,比如“小吃”。它一共会输出100页。

    可见:100页的搜索结果是淘宝的上限。(最多100页)

    Alt text

    2 . 分析网址结构:

    当我们点击页面进行浏览时,我们发现不同的页面的网址有规律,并且下面是我们找到的规律:

    1. 红色部分是一模一样的。
    2. 删除红色部分,将剩下的组成网址,一样可以正常的浏览原网页。
    3. q= 后面是“小吃”的编码形式。
    4. s= 后面的数值等于 44*(当前页面-1)

    Alt text

    开始写爬虫程序(taobao.py 文件)

    创建一个爬虫文件(taobao.py 文件)

    cd thirdDemo
    scrapy genspider -t basic taobao taobao.com

    Alt text

    使用PyCharm软件开发,使用PyCharm软件打开 thirdDemo项目。

    Alt text

    添加需要使用的存储容器对象(items.py文件)

    先到 items.py 文件里面的ThirddemoItem()函数里面创建存储用到容器(类的实例化对象)

    class ThirddemoItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        title = scrapy.Field()
        link = scrapy.Field()
        price = scrapy.Field()
        comment = scrapy.Field()
        pass

    Alt text

    得到搜索关键字对应的所有搜索页面(taobao.py文件)

    在回调函数parse()中,建立一个变量(key)来存储关键词(零食)。然后在使用一个for循环来爬取所有的网页。然后使用scrapy.http里面的Request 来在parse()函数返回(返回一个生成器(yield))一个网页源代码:

    # -*- coding: utf-8 -*-
    import scrapy
    from scrapy.http import Request
    
    class TaobaoSpider(scrapy.Spider):
        name = "taobao"
        allowed_domains = ["taobao.com"]
        start_urls = ['http://taobao.com/']
    
        def parse(self, response):
            key = '小吃'
            for i in range(0, 2):
                url = 'https://s.taobao.com/search?q=' + str(key) + '&s=' + str(44*i)
                print(url)
                yield Request(url=url, callback=self.page)
            pass
    
        def page(self, response):
            pass

    Alt text

    (注意:我们上面通过观察网页已经知道了,搜索得到的页面有100页,但是我们现在是测试阶段,不爬这么多页,上面的代码我们只爬了2页)


    运行一下:

    Alt text

    程序没有问题。


    得到所有商品的id

    我们现在的目标是得到搜索页面中所有商品的链接。

    Alt text

    现在,我们观察搜索页面的源代码,我们找这些商品链接的规律,能否通过什么商品id之类的信息,然后通过商品id来构造出商品的链接网址。

    幸运的是:确实可以这么做。

    我发现,不管是搜索的商品,不管是在淘宝里、天猫里、天猫超市里,商品的链接网址都可以用下面的格式去构造:

    https://item.taobao.com/item.htm?id=商品的id

    所以,现在我们要做的是:先提取商品的id:(使用正则表达式)

    对搜索结果的网页随便一个地方右键:查看网页源代码(V)

    (我发现:通过在浏览器中按F12 和 右键来 查看网页源代码 这两种查看源代码得到的源代码不一样,后者得到的源代码和爬虫爬取的源代码一致,而前者和爬虫爬取的不一致。)

    所有我们不能使用Xpath表达式来用过标签获取商品id了。只能使用正则表达式了。

    我想可能的原因是:搜索页面可能是动态构造出来的,所以使用Xpath表达式是不能对这种网址的源码进行提取信息的。(我瞎想的,不知道是否正确。不过事实其实是:使用Xpath表达式是提取不了有效信息的。)

    Alt text

    然后随便点击进入一个商品的链接网页,在这个网页的网址里面就可以找到这个商品的id:

    Alt text

    然后在刚刚打开的源代码中,查找这个id:

    Alt text

    我们通过观察发现,使用"nid":"就可以找到这个搜索结果页面里面所有商品的id:

    Alt text

    这个页面里面一共是36个商品,没错。

    Q: 你可能发现了,这个搜索网页里面搜索到结果是48个商品,我们得到的是36个,是不是少了?

    A: 没有少,这就是淘宝的营销策略。一个搜索页面一共有48个商品,但是其中有10多个商品是重复的!其中甚至有个商品在这个搜索页面中重复出现了三次,不信,你可以仔细的找找。

    所以,商品的id可以使用下面的正则表达式获取:

    '"nid":"(.*?)"'

    我们在page()方法中得到爬取到的网页源代码的 body 标签里面的所有信息:

    先声明一点:

    爬取到的网页源代码是:以网页源代码中指定的编码方式编码得到的bytes信息。

    Alt text

    我们需要得到对应的解码信息:

    参考网站:Python3 bytes.decode()方法

            body = response.body.decode('utf-8')

    response.body 它默认是二进制格式,所以我们在使用它之前要给它解码:decode('utf-8'),为了避免出错,我给它传第二个参数:ignore

    page()函数中的代码现在是下面这个样子的:

        def page(self, response):
            body = response.body.decode('utf-8','ignore')
            pattam_id = '"nid":"(.*?)"'
            all_id = re.compile(pattam_id).findall(body)
            print(all_id)
            pass

    运行试试看:

    Alt text


    得到所有商品的链接网址

    现在得到了所有商品的ip,现在通过这些ip,构造出所有商品的网址。得到了链接后,就可以去爬这个网页的源代码了:(下面的代码中,在next()方法中将商品的网页网址打印了出来)

    import re
        def page(self, response):
            body = response.body.decode('utf-8','ignore')
            pattam_id = '"nid":"(.*?)"'
            all_id = re.compile(pattam_id).findall(body)
            # print(all_id)
            for i in range(0, len(all_id)):
                this_id = all_id[i]
                url = 'https://item.taobao.com/item.htm?id=' + str(this_id)
                yield Request(url=url, callback=self.next)
                pass
            pass
    
        def next(self, response):
            print(response.url)
            pass

    运行试试看:(自动的将网址调整到正确的网址上。比如天猫或者天猫超市之类的子域名)

    Alt text


    获取商品的具体信息(taobao.py 文件)

    获取商品的名字

    现在在next()回调函数中实例化一个开始时在items.py文件里面创建的项目的存储容器对象。然后,我们就可以直接使用它了。

    所以现在在 taobao.py 文件的上面添加这个文件:

    from thirdDemo.items import ThirddemoItem

    现在我们要得到商品的标题。

    我们尽量从源代码中的信息提取,如果源代码中没有的信息,我们在使用抓包的凡是提取。

    标题是可以直接在源代码中提取的:(观察网页源代码,直接中Xpath表达式)

    天猫或者天猫超市的商品的标题可以使用下面的Xpath表达式提取:

    title = response.xpath("//div[@class='tb-detail-hd']/h1/text()").extract()

    淘宝的商品的标题可以使用下面的Xpath表达式提取:

    title = response.xpath("//h3[@class='tb-main-title']/@data-title").extract()

    所以,这里提取标题,我们需要一个判断语句,判断这个商品的网址链接是天猫的还是淘宝的。

    伪码如下:

    if 不是淘宝的网址:
        title = response.xpath("//div[@class='tb-detail-hd']/h1/text()").extract() # 天猫或者天猫超市
    else:
        title = response.xpath("//h3[@class='tb-main-title']/@data-title").extract() # 淘宝

    我们的判断标准就是商品网址的子域名。子域名大致一共有三种:detail.tmall(天猫)、chaoshi.detail.tmall(天猫超市)、item.taobao(淘宝)

        def next(self, response):
            # print(response.url)
            url = response.url
            pattam_url = 'https://(.*?).com'
            subdomain = re.compile(pattam_url).findall(url)
            # print(subdomain)
            if subdomain[0] != 'item.taobao':
                title = response.xpath("//div[@class='tb-detail-hd']/h1/text()").extract()
                pass
            else:
                title = response.xpath("//h3[@class='tb-main-title']/@data-title").extract()
                pass
            self.num = self.num + 1;
            print(title)
            pass

    运行试试看:

    Alt text

    有的时候,偶尔会得到几个 [],这是因为,你爬的太快的,淘宝的服务器没有同意你爬取这个商品的网页。(所以提高防反爬机制,效果会好一些。)

    Alt text

    获取商品的链接网址(taobao.py 文件)

    (直接得到)

            item['link'] = response.url

    获取商品的价格信息(原价)(taobao.py 文件)

    正常的价格可以在商品网页的源代码里面获取,但是淘宝价(促销价)在商品源代码里面没有,这时就需要通过抓包来获取。

    淘宝:

    Alt text

    天猫:

    Alt text

    我们先获取正常的价格。这里也需要分淘宝和天猫,它们获取正常价格的Xpath表达式或者正则表达式不同。

    注意:这里总结表达式,通过对商品页面右键 -> 查看网页源代码 的方式查看源代码。

            if subdomain[0] != 'item.taobao':
                pattam_price = '"defaultItemPrice":"(.*?)"'
                price = re.compile(pattam_price).findall(response.body.decode('utf-8', 'ignore')) # 天猫
                pass
            else:
                price = response.xpath("//em[@class = 'tb-rmb-num']/text()").extract() # 淘宝
                pass
            print(price)

    提取商品的累计评论数量:(使用抓包的方式)(taobao.py 文件)

    淘宝:

    Alt text

    天猫:

    Alt text

    可以使用 : Fiddler4抓包软件 或者 浏览器按F12->Network->Name->Response查看抓包信息

    这里,我通过浏览器进行抓包,找到了评论数所在的包:(一个一个的找)

    淘宝:

    Alt text

    观察这个包的网址:

    Alt text

    这个网址,我们可以在浏览器中复制,再访问以下:(是可以正常访问的)

    Alt text

    https://rate.taobao.com/detailCommon.htm?auctionNumId=533237707421&userNumId=1990097437&ua=097UW5TcyMNYQwiAiwQRHhBfEF8QXtHcklnMWc%3D%7CUm5Ockt%2BQ3dDfkB8R35Eey0%3D%7CU2xMHDJ7G2AHYg8hAS8XKQcnCVU0Uj5ZJ11zJXM%3D%7CVGhXd1llXGlUYFRpV2tQaVFvWGVHekV8RHtBf0Z%2FQXRKdUx1T3VOYDY%3D%7CVWldfS0TMw8xBD8fIAAubQslcyU%3D%7CVmJCbEIU%7CV2lJGSQEORklGCMYOAI%2FADkZJREuEzMPMgc6GiYSLRAwDDEJNGI0%7CWGFcYUF8XGNDf0Z6WmRcZkZ8R2dZDw%3D%3D&callback=json_tbc_rate_summary

    我发现上面的这个网址可以缩减为:

    https://rate.taobao.com/detailCommon.htm?auctionNumId=533237707421
    https://rate.taobao.com/detailCount.do?_ksTS=1480993623725_99&callback=jsonp100&itemId=533237707421

    而这个533237707421就是商品的id。好了,找到这个网址的规律,现在可以> 手动构造这个评论数的网址了:

    天猫:

    Alt text

    https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=35338957824&spuId=235704813&sellerId=628189716&_ksTS=1480992656788_203&callback=jsonp204

    可以缩减为:

    https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=35338957824

    最后,我们发现:不管是淘宝还是天猫,都可以使用下面这个构造方式来得到含有正确评论数量的网址:

    https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=商品id

    注意:使用https://rate.taobao.com/detailCommon.htm?auctionNumId=商品id 这种网址也可以,但是在对天猫商品得到评价数量和网页里面显示的不同。所以我们不使用这个构造方法。

    Alt text

    Alt text

    所以通过商品id就可以得到含有评论数量信息的包的网址。现在在next()方法中需要通过商品的URL获取商品的id。

    Alt text

    我们从上面的图中看到:天猫和淘宝的网址不同,所以,从网址中获取商品id的正则表达式也就不同。下面的代码的功能就是从商品的url中提取商品id:

            # 获取商品的id(用于构造商品评论数量的抓包网址)
            if subdomain[0] != 'item.taobao':  # 如果不属于淘宝子域名,执行if语句里面的代码
                pattam_id = 'id=(.*?)&'
                this_id = re.compile(pattam_id).findall(url)[0]
                pass
            else:
                # 这种情况是不能使用正则表达式的,正则表达式不能获取字符串最末端的字符串
                pattam_id = 'id=(.*?)$'
                this_id = re.compile(pattam_id).findall(url)[0]
                pass
            print(this_id)

    注意:$ : 在正则表达式里面的作用是:匹配字符串末尾。

    举例:当url = 'https://item.taobao.com/item.htm?id=535023141744' 时,这是一个淘宝网站里面的一个商品,现在我们想得到这个网址里面的商品id。

    如果你把正则表达式写成这个样子:pattam_id = 'id=(.*?)',是匹配不到结果的(商品id)。

    正则表达式是通过字符串上下文来匹配你需要的信息的,如果只有“上文”,没有“下文”时,对于使用正则表达式匹配字符串末端字符串,需要在正则表达式中使用$


    运行试试看,一切都在掌控之中。

    构造具有评论数量信息的包的网址,并获取商品的评论数量

    得到目标抓包网址,获取它的源代码,然后提取评论数量:

    import urllib
            # 构造具有评论数量信息的包的网址
            comment_url = 'https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=' + str(this_id)
    
            # 这个获取网址源代码的代码永远也不会出现错误,因为这个URL的问题,就算URL是错误的,也可以获取到对应错误网址的源代码。
            # 所以不需要使用 try 和 except urllib.URLError as e 来包装。
            comment_data = urllib.request.urlopen(comment_url).read().decode('utf-8', 'ignore')
            pattam_comment = '"rateTotal":(.*?),"'
            comment = re.compile(pattam_comment).findall(comment_data)
            # print(comment)
            item['comment'] = comment

    现在返回item对象:

            yield item

    Alt text


    现在,我们就可以在pipline.py文件里面来对我们得到的这些商品数据进行一些操作了,比如打印到终端或者保存到数据库中。

    但在这之前,我们需要设置一下settings.py文件,将下面的代码的注释去掉:

    Alt text


    pipline.py文件中对taobao.py爬虫文件返回的item对象进行处理(比如打印到终端,或者保存到数据库中)

    将得到的信息打印到终端中:

    class ThirddemoPipeline(object):
        def process_item(self, item, spider):
            title = item['title'][0]
            link = item['link']
            price = item['price'][0]
            comment = item['comment'][0]
            print('商品名字', title)
            print('商品链接', link)
            print('商品正常价格', price)
            print('商品评论数量', comment)
            print('------------------------------\n')
            return item

    运行试试看:

    Alt text


    下面是将得到的信息保存到数据库中的操作:

    第一件事情就是 启动数据库,启动数据库的代码一般我们是将它写到默认的__init__(self)函数中,这个方法就是最开始做的事情。

    要想连接到数据库,首先要有数据库:使用MySQL数据库

    在python上要想使用MySqL数据库,需要先安装pymysql库这个模块。

    Alt text

    有打开数据库的函数,就要有关闭数据库的方法。

    Alt text

    现在,我们在process()函数中处理数据,将数据插入到数据库里面。并且加一个异常处理,因为我不希望程序运行的时候会出现错误而终止,并且我也不想

    Alt text


    请访问:http://www.aobosir.com/

    展开全文
  • 爬虫作业:1.选一个自己感兴趣的主题(所有人不能雷同)。2.用python 编写爬虫程序,从网络上爬取相关...6.最后提交爬取的全部数据、爬虫及数据分析源代码。爬虫作业爬取的网站:http://sports.sina.com.cn/n...

    爬虫大作业:

    1.选一个自己感兴趣的主题(所有人不能雷同)。

    2.用python 编写爬虫程序,从网络上爬取相关主题的数据。

    3.对爬了的数据进行文本分析,生成词云。

    4.对文本分析结果进行解释说明。

    5.写一篇完整的博客,描述上述实现过程、遇到的问题及解决办法、数据分析思想及结论。

    6.最后提交爬取的全部数据、爬虫及数据分析源代码。

    爬虫大作业爬取的网站:http://sports.sina.com.cn/nba/。

    1037790-20180429223926069-304371733.png

    爬虫源代码:

    from urllib importrequestimportnumpy as npimportrequestsimportrefrom PIL importImagefrom bs4 importBeautifulSoupfrom datetime importdatetimefrom wordcloud importWordCloud, ImageColorGeneratorimportmatplotlib.pyplot as pltdefgetNewsDetail(Url):

    resd=requests.get(Url)

    resd.encoding= 'utf-8'soupd= BeautifulSoup(resd.text, 'html.parser') #打开新闻详情并解析

    news ={}

    news['76人总冠军'] = soupd.select('.main-title')[0].text.rstrip()print(news)return(news);

    newslist=[]def getListPage(newsUrl): #9. 取出一个新闻列表页的全部新闻 包装成函数def getListPage(pageUrl)

    res =requests.get(newsUrl)

    res.encoding= 'utf-8'soup= BeautifulSoup(res.text, 'html.parser')for news in soup.select('.news-list-a ul li'):

    Url= news.select('a')[0].attrs['href']#filmslist.append(getFilmsDetail(Url))

    print(Url)

    newslist.append(getNewsDetail(Url))return(newslist)#print(res.text)

    newstotal=[]

    firstPageUrl='http://sports.sina.com.cn/nba/'newstotal.extend(getListPage(firstPageUrl))

    f= open('nba.txt', 'w', encoding='utf-8')

    txtName= "nba.txt"f= open(txtName, "a+")

    f.write(str(newstotal))

    f.close()for news innewstotal:print(news)

    f=open('nba.txt','r',encoding='GBK').read()

    font=r'C:\Windows\Fonts\simkai.ttf'a=np.array(Image.open("enbide.jpg"))

    wordcloud=WordCloud( background_color="white",font_path=font,width=1000,height=860,mask=a,margin=2).generate(f)

    imagecolor=ImageColorGenerator(a)

    plt.imshow(wordcloud)

    plt.axis("off")

    plt.show()

    wordcloud.to_file('weibo.jpg')

    python运行后的.txt文件:

    1037790-20180429224321791-1661227272.png

    生成词云:

    1037790-20180429224551356-158818149.png

    1037790-20180429224528342-1688548068.png

    总结:

    在这次的python大作业中,遇到的做大的问题就是python的配置问题,wordcloud组件的导入出现的问题让我花费了许多的时间去解决。

    1.用终端的命令下载wordcloud:

    在cmd终端中,运用命令pip install wordcloud,进行安装wordcloud出现安装失败的问题。

    2.然后百度后在这个网站上https://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud下载whl文件,在终端上进行安装。

    3.通过研究解决和同学们的帮忙,终于解决了wordcloud组件的安装问题。

    这是安装完成后的:

    1037790-20180429225345462-2039454987.png

    代码文件类:

    根据老师在课上的授课,我了解到了关于词频数据分析的有关的知识,对于词云上的一些问题通过自在百度上的学习和室友同学的帮忙也都顺利解决了!

    主题爬取:

    这次爬取的主题也是自己比较关注篮球比赛--NBA的赛事。这次的大作业是自己比较感兴趣的,在对数据的爬取时感觉很有趣。同时自己也受益颇多!

    展开全文
  • 考试周正好部分课程开始结课,可以有块的时间来学习。下面介绍一下学习目标: 这篇博文会完成这部分视频的笔记和练习。 6-【作业】内涵段子爬虫作业 这里按照老师给的url:www.neihanshequ.com已经找不到...
  • 之前卡在数据解析部分,前十个,从跟随式,到自己思考,爬取老师示范讲解的不同部分的内容,再到拿到先自己分析,在思考方式上有比较的进步。花费的时间也有些长了,好在,回归实验室生活后。解析老师的任务,...
  • 前言本文的文字图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。本节中,我们以今日头条为例来尝试通过分析Ajax请求来抓取网页数据的方法。这次要抓取的...
  • 在当前数据爆发的时代,数据分析行业势头强劲,越来越多的人涉足数据分析领域。面对大量数据,人工获取信息的成本高、耗时长、效率低,那么是否能用代码去完成大量复杂的工作,从而从网络上获取到目标信息?由此,...
  • 本系列文章是Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警AI和NLP应用等。前文分享了数据抓取,并将数据存储至本地,最后...
  • | 夕颜思来想去,虽然很忙,但还是挤时间针对这次肺炎疫情写个Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警AI和NLP应用等...
  • 2 ) 抓取各电商的评论销量数据,对各种商品(颗粒度可到款式)沿时间序列的销量以及用户的消费场景进行分析。Python资源共享群:6260171233)还可以根据用户评价做情感分析,实时监控产品在消费者心目中的形象...
  • 作者 | 杨秀璋来源 | CSDN博客专家Eastmount责编 | 夕颜思来想去,虽然很忙,但还是挤时间针对这次肺炎疫情写个Python大数据分析系列博客,包括网络爬虫、可视化分析、G...
  • 正则表达式是处理字符串的强大工具,它有自己特定的语法结构,对于爬虫来说,它可以帮我们从HTML例提取我们想要的信息,实际上正则表达式应用非常广泛,如数据挖掘、数据分析网络爬虫、输入有效性验证等。...
  • 该资源是针对这次肺炎疫情写个Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警AI和NLP应用等。希望该系列线上远程教学对您...
  • 本篇报告主要聚焦于「恶意爬虫」,不讨论搜索引擎爬虫及合法爬虫等。 爬虫的分类 按爬虫功能,可以分为网页爬虫和接口爬虫。 网页爬虫:以搜索引擎爬虫为主,根据网页上的超链接进行遍历爬取。 接口爬虫:通过...
  • 文章目录《基于Python的大数据分析基础实战》精简读书笔记-标记试INTRODUCTIONLIST OF KEY POINTSPython基础部分数据处理部分数据分析数据可视化网络爬虫技术Python 常用包整理 INTRODUCTION 这是一本写给初学者的...
  • 在互联网时代,爬虫绝对是一项非常有用的技能。借助它,你可以快速获取大量的数据并自动分析,或者帮你完成大量重复、...-- 爬虫,即网络爬虫,大家可以理解为在网络上爬行的一只蜘蛛,互联网就比作一张网,而爬虫...
  • C++网络爬虫项目

    2018-07-04 00:59:17
    的多路输入输出循环,一旦发现某个与服务器相连的套接字有数据可读,即创WEBCRAWLER 网络爬虫实训项目 10 建接收线程,后者负责抓取页面内容,而前者继续于多路输入输出循环中等待 其它套接字上的I/O事件。 3.2. ...
  • 网络爬虫的连接网络设置连接读取时间,避免无限制的等待。为了适应不同需求,使网络爬虫可以根据预先设定的主题实现对特定主题的爬取。研究网络爬虫的原理并实现爬虫的相关功能,并将爬去的数据清洗之后存入...
  • 爬虫大作业

    2018-04-29 23:08:00
    爬虫作业: 1.选一个自己感兴趣的主题(所有人不能雷同)。 2.用python 编写爬虫程序,从网络上爬取相关主题的数据...6.最后提交爬取的全部数据、爬虫及数据分析源代码。 爬虫作业爬取的网站:http://sports...
  • 详细可参考 (1)书箱:《这就是搜索引擎》《自己动手写网络爬虫》《解密搜索引擎打桩实践》 (2)【搜索引擎基础知识1】搜索引擎的技术架构 ...2、数据分析处理层:将从互联网上获取到的数...
  • | 夕颜思来想去,虽然很忙,但还是挤时间针对这次肺炎疫情写个Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警AI和NLP应用等...
  • | 夕颜思来想去,虽然很忙,但还是挤时间针对这次肺炎疫情写个Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警AI和NLP应用等...
  • 1 网络爬虫 1.1 背景引入 随着互联网的迅速发展,万维网已成为大量信息的载体,越来越多的网民可以通过互联网搜索引擎获取所需要的信息。 事实上,市面上通用的搜索引擎是存在一定局限性的: 搜索引擎返回的结果包.

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 318
精华内容 127
关键字:

网络爬虫及大数据分析

爬虫 订阅