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

一.前述

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

二.工具

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

三.详细解析代码

创建scrapy我们只需要在cmd中,scrapy startproject 文件名,这样就可以创建出以下文件了
《scrapy+jieba:从文字中了解它人内心》 此图来源网络

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

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

《scrapy+jieba:从文字中了解它人内心》 scrapy的结构图.png

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

《scrapy+jieba:从文字中了解它人内心》 image.png

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

《scrapy+jieba:从文字中了解它人内心》 image.png

四.观察网页

《scrapy+jieba:从文字中了解它人内心》 image.png

F12进入开发者工具,主要是想看一下网页时以什么形式加载的,现在大部分网页都会是动态加载的,所以我们要抓包看一下。

我现在访问的网页是:
https://www.jianshu.com/u/1964293091a3

《scrapy+jieba:从文字中了解它人内心》 image.png

从图片中可以看到文章真正的网址确实不是浏览器访问的网址,当我下滑的时候还会出现更多的文章地址

《scrapy+jieba:从文字中了解它人内心》 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)

《scrapy+jieba:从文字中了解它人内心》 cookie.png

《scrapy+jieba:从文字中了解它人内心》 图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)

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

《scrapy+jieba:从文字中了解它人内心》 image.png

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

《scrapy+jieba:从文字中了解它人内心》 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

《scrapy+jieba:从文字中了解它人内心》 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文本

《scrapy+jieba:从文字中了解它人内心》 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)))

《scrapy+jieba:从文字中了解它人内心》 生成结果.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()

《scrapy+jieba:从文字中了解它人内心》 Figure_1.png

六.结尾

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

    原文作者:Twinklere
    原文地址: https://www.jianshu.com/p/9ab1d62335c6
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞