一.前述
因为最近在学习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的一系列组件
我们还需要进入spider文件夹创建 scrapy genspider [文件名] [mydomain.com] spider文件
image.png
这个文件用来编写的可定制化的部分,负责解析response,产生items和url.(我们主要在这里写代码)
创建好之后会出现
image.png
四.观察网页
image.pngF12进入开发者工具,主要是想看一下网页时以什么形式加载的,现在大部分网页都会是动态加载的,所以我们要抓包看一下。
我现在访问的网页是: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文本
这样,我们就可以用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框架写出来的,写了一段时间,主要原因还是自己喜欢学这些东西,如果有喜欢的爬虫或者是其他计算机方面的爱好者也可以联系我哈~
好啦!感谢大家的阅读~
网友评论