国社科项目数据爬取

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()

申报类型的Bar图

data['立项时间'].value_counts().plot(kind='pie',autopct='%1.2f%%',explode = np.linspace(0,1,36))
plt.show()

申报时间的Pie图
以上只是提供思路,可以根据个人需要自行分析。

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

除此之外,还可以对院校、区域等信息进行分析,或是爬取自科基金分析,本文仅提供思路,希望对大家有所帮助。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值