国社科项目爬取分析
1. 爬取网站
2. 爬取目标信息
主要爬取基金项目的类别、名称、立项时间、项目负责人、职称、工作单位这六种信息。
3. 爬取准备工作
- 环境配置:Python 3 + Scrapy
- 工具准备:Sublime Text 3 + XPath Helper
- 网页源码分析
4. 爬取项目
4.1 创建项目
- 打开命令提示符(cmd):Win + R
- 进入自定文件夹:cd xxx
- 创建爬虫项目:
scrapy startproject gskSpider
4.2 创建爬虫文件
- 根据提示进入项目:
cd gskSpider
- 创建爬虫并指定爬取的域:
scrapy genspider gsk fz.people.com.cn
4.3 编写配置文件
items.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class GskspiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
category = scrapy.Field() #项目类别
name = scrapy.Field() #项目名称
time = scrapy.Field() #立项时间
person = scrapy.Field() #项目负责人
protitle = scrapy.Field() #职称
school = scrapy.Field() #工作单位
settings.py
# 以下设置皆是为了防止爬虫生成的csv文件乱码
FEED_EXPORT_ENCODING ='utf-8'
FEED_EXPORT_ENCODING = 'gb18030'
# Obey robots.txt rules
# 非商用因此设置爬虫规则为False
ROBOTSTXT_OBEY = False
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
#'Cookie': 'sso_c=0; sfr=1; wdcid=7dda1ce5d1e19cb5; PHPSESSID=v5k1j4q09brjp7l4d8mig0qvg1; Hm_lvt_dde6ba2851f3db0ddc415ce0f895822e=1578573092,1578649866; Hm_lpvt_dde6ba2851f3db0ddc415ce0f895822e=1578653914',
'Host': 'fz.people.com.cn',
'Referer': 'http://fz.people.com.cn/skygb/sk/index.php/Index/seach?xmtype=%E4%B8%80%E8%88%AC%E9%A1%B9%E7%9B%AE&xktype=%E7%AE%A1%E7%90%86%E5%AD%A6&p=2',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
}
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
# 下方代码注释取消
ITEM_PIPELINES = {
'gskSpider.pipelines.GskspiderPipeline': 300,
}
4.4 元素定位
使用Chrome浏览器中的XPath Helper插件来对网页源代码进行分析,准确定位所要爬取的内容。
上图所示便是借助XPath Helper进行的项目名称定位结果,同样的可以写出另外几种要爬取信息的XPath代码,最终将爬虫文件gsk.py
代码展示如下。
# -*- coding: utf-8 -*-
import scrapy
class GskSpider(scrapy.Spider):
name = 'gsk'
allowed_domains = ['fz.people.com.cn']
start_urls = ['http://fz.people.com.cn/skygb/sk/index.php/Index/seach?xktype=%E7%AE%A1%E7%90%86%E5%AD%A6&p=1']
def parse(self, response):
# 选择所有网址,由于这个网站的网页编码是有规律可循的,因此我认为用for循环要比专门设计翻页功能更便捷,当然也可能是我太菜哈哈哈
for i in range(1,189):
url = "http://fz.people.com.cn/skygb/sk/index.php/Index/seach?xktype=%E7%AE%A1%E7%90%86%E5%AD%A6&p=" + str(i)
if url:
yield scrapy.Request(url, callback=self.parseDetail)
def parseDetail(self, response):
# 选择内容 /html/body/div[3]/table/tbody/tr/td[2]/div/div/table/tbody/tr[1]/td[4]/span 这是第一个项目名称
selectors = response.xpath("//div[@class='jc_a']/table//tr")
for selector in selectors:
gsk_id = selector.xpath(".//td[1]/span/@title").get(default='') #项目批准号
gsk_category = selector.xpath(".//td[2]/span/@title").get(default='') #项目类别
gsk_name = selector.xpath(".//td[4]/span/@title").get(default='') #项目名称
gsk_time = selector.xpath(".//td[5]/span/@title").get(default='') #立项时间
gsk_person = selector.xpath(".//td[6]/span/@title").get(default='') #项目负责人
gsk_protitle = selector.xpath(".//td[7]/span/@title").get(default='') #职称
gsk_school = selector.xpath(".//td[8]/span/@title").get(default='') #工作单位
# 一定要是字典格式
items = {
"项目批准号": gsk_id,
"项目类别": gsk_category,
"项目名称": gsk_name,
"立项时间": gsk_time,
"项目负责人": gsk_person,
"职称": gsk_protitle,
"工作单位": gsk_school,
}
# yield是一个生成器 类似于return
yield items
4.5 爬取结果呈现
不知道为什么,这个网站非常神奇,花了很长时间调试出来这样奇怪的XPath代码表示,但是最终成功跑下来了数据,通过在cmd输入scrapy crawl gsk -o gsk.csv
,保存为csv文件。
5. 数据分析
5.1 简图分析
以下绘图参考挖掘机小王子的一篇知乎文章(Python 拉钩数据采集与可视化)
5.1.1 引入几个必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl # 配置字体
import jieba # 分词
import jieba.analyse
import wordcloud
import string
import re # 正则表达式库
from PIL import Image # 图像处理库
5.1.2 配置绘图环境
因为我在绘图过程中出现了很多问题,因此提前设置好。
mpl.use('qt4agg')
#指定默认字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['font.family']='sans-serif'
#解决负号'-'显示为方块的问题
mpl.rcParams['axes.unicode_minus'] = False
# 配置绘图风格
plt.rcParams["axes.labelsize"] = 16.
plt.rcParams["xtick.labelsize"] = 14.
plt.rcParams["ytick.labelsize"] = 14.
plt.rcParams["legend.fontsize"] = 12.
plt.rcParams["figure.figsize"] = [15., 15.]
5.1.3 导入数据文件
data = pd.read_csv('gsk.csv',encoding='gbk')
5.1.4 绘图
from matplotlib.pyplot import MultipleLocator # 从 pyplot 导入 MultipleLocator 类,这个类用于设置刻度间隔
plt.figure(figsize=(10,10))
x_major_locator=MultipleLocator(1)
# 把 x 轴的刻度间隔设置为 1,并存在变量里
ax=plt.gca()
#ax 为两条坐标轴的实例
ax.xaxis.set_major_locator(x_major_locator)
# 把 x 轴的主刻度设置为 1 的倍数
data['项目类别'].value_counts().plot(kind='bar', width=0.5, rot=0, color='b')
plt.show()
data['立项时间'].value_counts().plot(kind='pie',autopct='%1.2f%%',explode = np.linspace(0,1,36))
plt.show()
以上只是提供思路,可以根据个人需要自行分析。
5.2 词频分析
5.2.1 文件预处理
词频分析只需要项目名称,因此先将其提取出来,并生成新的文件,便于下一步处理。
title = data['项目名称']
title.to_csv('gsk_title.csv', index=None, encoding='utf_8_sig') # 不要索引号,并且防止乱码
然后将新生成的csv文件中的项目名称进行分词,并生成txt文件进行存储。
wf = open('clean_title.txt','w+')
for line in open('gsk_title.csv'):
item = line.strip('\n\r').split('\t') #制表格切分
# print item[1]
tags = jieba.analyse.extract_tags(item[0]) #jieba分词
tagsw = ",".join(tags) #逗号连接切分的词
wf.write(tagsw)
wf.close()
5.2.2 词频统计及绘制词云
对分好的词进行词频统计,生成字典类型的{词语:词频}并存储在csv文件中。
word_lst = []
word_dict= {}
with open('clean_title.txt') as wf,open("word.csv",'w') as wf2: #打开文件
for word in wf:
word_lst.append(word.split(',')) #使用逗号进行切分
for item in word_lst:
for item2 in item:
if item2 not in word_dict: #统计数量
word_dict[item2] = 1
else:
word_dict[item2] += 1
for key in word_dict:
print(key,word_dict[key])
wf2.write(key+' '+str(word_dict[key])+'\n') #写入文档
然后绘制词云图,最终呈现效果如下。
txt = open("clean_title.txt", 'r', encoding="gbk").read()
mask = np.array(Image.open('map.jpg')) # 定义词频背景,这里的map是我找好的一个地图文件,可以根据喜好更换
w = wordcloud.WordCloud(background_color="white", font_path="msyh.ttc", mask=mask,# 设置背景图
max_words=200, # 最多显示词数
max_font_size=100) # 字体最大值
w.generate(" ".join(lists))
w.to_file("word.png")
5.2.3 pyecharts绘制词云
最近刚刚学了一点pyecharts的知识,用这个绘图非常好看而且具有交互性,下面以词云图为例看一看效果。
from pyecharts import options as opts
from pyecharts.charts import Page, WordCloud
# 声明一个空系列数据项,来保存文本文件数据
words = []
# 打开文本文件
file = open('word.txt','r')
# 遍历文本文件的每一行,strip可以移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
for line in file.readlines():
line = line.strip()
k = line.split(' ')[0]
v = line.split(' ')[1]
words.append((k,v))
# 关闭文件
file.close()
def wordcloud_base() -> WordCloud:
c = (
WordCloud(init_opts = opts.InitOpts(page_title = "自定义网页名"))
.add("", words, word_size_range=[2, 100],
shape = 'cardioid' # 词云图轮廓,有 'circle', 'cardioid', 'diamond', 'triangle-forward', 'triangle', 'pentagon', 'star' 可选
# 此外还可以引入pyecharts.globals.SymbolType,里面也有几种类型
)
.set_global_opts(title_opts = opts.TitleOpts(title = "项目名称词云图"))
)
return c
wordcloud_base().render('WordCloud.html')
这个图可选形状不是很多,效果看起来也一般吧,不过交互性是一大亮点,绘制其他图效果更佳,想进一步了解可以查看官方文档(pyecharts官方网站)。
5.3 进一步筛选
可以进一步根据需要或是高频词汇进行筛选,获得更精确的数据。
d1 = data['项目名称'].astype('str')
t = data.loc[d1.str.contains('博弈')] # 很好理解,使用了str.contains(),筛选含有"隐私"的
print(t) # 这种方式生成的是文本
data_new = data[data['项目名称'].str.contains(r'.*?博弈.*')]
data_new # 这种方式生成的是dataframe
除此之外,还可以对院校、区域等信息进行分析,或是爬取自科基金分析,本文仅提供思路,希望对大家有所帮助。