scrapy+jieba:从文字中了解它人内心

作者: Twinklere | 来源:发表于2018-01-25 23:26 被阅读0次

    一.前述

    因为最近在学习scrapy框架,而且框架涉及到的内容也比较多,所以就想着写一篇文章来巩固一下scrapy框架的知识。 那么问题来了,我应该爬什么东西呢?不巧想到了我同学在简书写了好多的文章(此处@不不不不不不热我的大佬同学),而且人的文章多数都是散文,像我这种理科男并且作文永远写不好的人,正好可以借鉴她的文章来做实例,间接性的引用人家的散文。

    二.工具

    • scrapy (安装scrapy同时需要安装以下工具,可能Twisted用pip会安装不上去,https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted,这个网页里面会有twisted的下载地址)
      scrapy安装
    • jieba分词(把中文按词组的形式切割开,很好用的)
    • wordcloud(云图,生成一张词图)

    三.详细解析代码

    创建scrapy我们只需要在cmd中,scrapy startproject 文件名,这样就可以创建出以下文件了 此图来源网络

    然后我们来具体了解以下各个文件的主要用途:

    • init.py 这个应该比较熟悉吧,项目的初始化文件。
    • items.py 定义我们爬取内容的相关属性
    • middlewares.py 中间件,用来处理爬虫的输入和请求输出(可以用来设置代理ip,还有response返回的值)
    • pipelines.py 这是一个独立的类,它接收到item的信息,并且做一些处理(像保存数据库,去重什么的)
    • setting.py 可以设置pipline或Spider的一系列组件
    scrapy的结构图.png

    我们还需要进入spider文件夹创建 scrapy genspider [文件名] [mydomain.com] spider文件


    image.png

    这个文件用来编写的可定制化的部分,负责解析response,产生items和url.(我们主要在这里写代码)
    创建好之后会出现


    image.png

    四.观察网页

    image.png
    F12进入开发者工具,主要是想看一下网页时以什么形式加载的,现在大部分网页都会是动态加载的,所以我们要抓包看一下。
    我现在访问的网页是:https://www.jianshu.com/u/1964293091a3
    image.png
    从图片中可以看到文章真正的网址确实不是浏览器访问的网址,当我下滑的时候还会出现更多的文章地址
    image.png
    所以我们请求的地址大致也明了了。开始写我们的spider。

    五.代码

    现在我们就要在spider里面写代码了
    jianshutest.py
    网页请求方法

    from scrapy import  Request,Spider
    import json
    
    
    from simpleBook.items import JianshuItem
    
    class JianshutestSpider(Spider):
        name = 'jianshutest'
        allowed_domains = ['www.jianshu.com']
        start_urls = ['http://www.jianshu.com/']
      
        def start_requests(self):
            #cookie:你登录的用户名和密码都会包含在cookie里面,登录之后就可以查到(见下图)
            cookies={'Cookie':'remember_user_token=W1syMzQ1MzA2XSwiJDJhJDEwJE9ZMzIubnpCb0lNNTljcUg2RnU3OWUiLCIxNTA5Nzc3NDI3LjUwNDk4ODciXQ%3D%3D--af364747dd6fde4d917738c0b0840d02da5a1298; _gat=1; _ga=GA1.2.958245445.1504323082; _gid=GA1.2.291615467.1509881668; Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1508066816,1508943110,1509777295,1509881668; Hm_lpvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1509886621; _m7e_session=11bbcabbcae48dd2cee207c683dcb867; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%222345306%22%2C%22%24device_id%22%3A%2215f5404a0055fc-03123bf21a3db8-e313761-2073600-15f5404a0069f0%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E8%87%AA%E7%84%B6%E6%90%9C%E7%B4%A2%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22https%3A%2F%2Fwww.baidu.com%2Flink%22%2C%22%24latest_referrer_host%22%3A%22www.baidu.com%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC%22%7D%2C%22first_id%22%3A%2215f5404a0055fc-03123bf21a3db8-e313761-2073600-15f5404a0069f0%22%7D'}
            #请求的url,注意因为网站是以json格式加载的,下滑网页会发现出现好多的XHR文件,page是不一样的,所以要遍历一下页数,我看了一下一共是17页,所以我们从1range到17
            url = 'http://www.jianshu.com/u/1964293091a3?order_by=shared_at&page={page}'
            for page in range(1,17):
                #现在不需要判断status了,直接用scrapy自带的Request方法就可以,(参数1:请求的url.参数2:做回调函数,也就是把返回的resoponse回调到第二个方法里.参数3:写入cookie)
                yield Request(url.format(page=page) , callback=self.first_parse,cookies=cookies)
    
    cookie.png
    图2.png

    请求完网页后,我们要做处理了,定义第一次解析:

        def first_parse(self, response):
          #把请求头写到代码中,模拟浏览器
          headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
                       '    Accept-Encoding': 'gzip, deflate, br',
                       '    Accept-Language': 'zh-CN,zh;q=0.9',
                       '    Cache-Control': 'max-age=0',
                       '    Connection': 'keep-alive',
    
                       '    Host': 'www.jianshu.com',
                       '    If-None-Match': 'W/"a2bf45c7e139d5c5890a6d1ad6946052"',
                       '    Upgrade-Insecure-Requests': '1',
                       '    User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
                       }
          #因为是js的文件,所以要json.loads解析一下
          js = json.loads(response.text)
          for jsl in js.get('notes'):
              print(jsl)
    

    打印一下,检查一下我们写的内容是否正确.


    image.png

    看图确实没有问题哈,我们可以看到网页中的包含的众多信息,有标题作者什么的,但是!并没有我们要的文章啊。从网页中我发现,每点击一个标题会进入到文章页面,所以我开始就觉得这里面应该会有每一篇文章对应的网址吧,可以现在看来并没有呀!于是我就点开文章页面观察了一下网址。


    image.png
    发现页面后面的尾数就是我们的slug呀,这样我把所有获取到slug加上前缀请求一下就可以了。
    具体代码:
        def first_parse(self, response):
          headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
                       '    Accept-Encoding': 'gzip, deflate, br',
                       '    Accept-Language': 'zh-CN,zh;q=0.9',
                       '    Cache-Control': 'max-age=0',
                       '    Connection': 'keep-alive',
    
                       '    Host': 'www.jianshu.com',
                       '    If-None-Match': 'W/"a2bf45c7e139d5c5890a6d1ad6946052"',
                       '    Upgrade-Insecure-Requests': '1',
                       '    User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
                       }
          js = json.loads(response.text)
          #因为json文件里有key值和value值,现在所有的网页信息都在note这个key值,所以要get一下
          for jsl in js.get('notes'):
              item = JianshuItem()
              #获取slug值
              if 'slug' in jsl:
                  article = jsl.get('slug')
                  #拼接网页
                  article_url = 'https://www.jianshu.com/p/'+ article
                  for fields in item.fields:
                    if fields in jsl:
                      #这里可以打印出item里所对应的值
                       # item[fields] = jsl[fields]
                        #print(item)
                         #递归请求到文章页
                        yield Request(article_url,callback=self.second_parse,headers=headers)
                    else:
                        pass
    
        def second_parse(self,response):
            #请求到文章页,用css选择器把文章选出来,然后输出
            article_title =response.css('.note .post .article .title::text').extract_first()
            article_content = response.css('.note .post .article .show-content p::text').extract()
            item = JianshuItem()
            item['article_title'] = article_title
            item['article_content'] = article_content
            yield item
    
    image.png

    我们把这些文字写出到txt文本。需要在piplines写入这一段代码,或者用其他方法( ̄□ ̄||我当年是用xml解析出来的)

    class TxtscrapyPipeline(object):
        def process_item(self, item, spider):
            # 获取当前工作目录
            base_dir = os.getcwd()
            fiename = base_dir + '/1.txt'
             # 从内存以追加的方式打开文件,并写入对应的数据
            with open(fiename, 'w') as f:
                f.write(str(item['article_content']))
                f.flush()
                return item
    

    把符号什么的都要去掉,我们可以得到这样的一个txt文本

    image.png
    这样,我们就可以用jieba进行分词了,创建了jb.py(千万不要把文件名命名为jieba.py),不然导包时候会错误。
    代码如下:
    import jieba
    from jieba.analyse import extract_tags
    from wordcloud import WordCloud,ImageColorGenerator
    import matplotlib.pyplot as plt
    from os import path
    #读取我们的txt文件
    def open_file():
        with open('article.txt','r')as f:
            file_content = f.read()
            cut_content(file_content,200)
            show_picture(file_content)
            f.close()
    
    def cut_content(file_content,max_words):
        #取txt文本里的关键词
        tags = extract_tags(file_content, topK=max_words)
        #定义为dict集合
        word_dict = dict()
        #jieba分词
        word_list = jieba.lcut(file_content)
        #遍历tags
        for tag in tags:
            #对tag计数
            freq = word_list.count(tag)
           #生成dict
            word_dict[tag] = freq
        for a in word_dict:
          #输出
            print(str(a) +':'+str(word_dict.get(a)))
    
    生成结果.png
    虽然有许多没用的词,但同时我们也看到了她内心一直要写出的词,(希望,父母,迷茫,孤独,签约。。。)
    生成云图:
    def show_picture(file_content):
        g = " ".join(jieba.cut(file_content))
        back_coloring = plt.imread(path.join("1487226734725.jpg"))  # 选取背景图片
        word_cloud = WordCloud(font_path='simsun.ttc',  # 设置字体
                               mask=back_coloring,  # 设置背景图片
                               background_color="white",  # 背景颜色
                               max_words=900,  # 词云显示的最大词数
                               max_font_size=50,  # 字体最大值
                               random_state=42)
        my_wordcloud = word_cloud.generate(g)  # 生成词云图
        plt.imshow(my_wordcloud)
        plt.axis("off")
        plt.show()
        word_cloud.to_file(path.join("jianshu.png"))  # 保存图片
    
    def main():
        open_file()
    
    if __name__ == '__main__':
        main()
    
    Figure_1.png

    六.结尾

    首先特别感谢我的同学@不不不不不不热允许我拿她的文章来做实例,写这篇文章完全会透露一点她的隐私,但她还是接受了。当然,从最后的结果我们也可以看出她确实是一个努力上进,并且还有点悲观的女孩。
    这篇文章主要是自己用来学scrapy框架写出来的,写了一段时间,主要原因还是自己喜欢学这些东西,如果有喜欢的爬虫或者是其他计算机方面的爱好者也可以联系我哈~
    好啦!感谢大家的阅读~

    相关文章

      网友评论

        本文标题:scrapy+jieba:从文字中了解它人内心

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