目录
- 1 文本数据采集
- 2 文本数据解析
- 3 文本数据分析
- 4 文本数据词云
- 5 文本数据分类与其它
1 文本数据采集
- 采集数据源:三板市场研报
- 采集样本数:全部采集,采集截至当前的所有三板研报
- 采集内容:序号 日期 报告类型 标题 机构 作者 研报内容
- 采集方法:爬虫采集,使用scrapy框架采集
- 存储格式:JSON格式或其它格式
代码示例与说明(注释中有详细信息)
class EastmoneySpider(scrapy.Spider):
name = "eastmoney"
allowed_domains = ["http://data.eastmoney.com", "data.eastmoney.com"]
"""
查看要爬取的主页面,查看网页源码或审查,发现如下链接,是数据表加载的js请求URL。
dataurl: "http://datainterface.eastmoney.com//EM_DataCenter/JS.aspx?type=SB&sty=SBSCYJ&st={sortType}&sr={sortRule}&p={page}&ps={pageSize}&js=var {jsname}={pages:(pc),data:[(x)]}{param}"
在使用时根据需要去除排序、请求格式等,使用如下start_urls可请求到所有的研报信息。
"""
start_urls = ['http://datainterface.eastmoney.com//EM_DataCenter/JS.aspx?type=SB&sty=SBSCYJ&ps=10000']
def parse(self, response):
dataArray = response.body.strip('\(\)\[\]').split("\"") # 对返回的研报信息根据\"进行split
marketArray = [each for each in dataArray if each != ',' and each != ''] # 去掉无效列表信息
# 对处理后的列表信息进行解析
for each in marketArray:
item = New3Item()
aList = each.split(",")
item['rep_id'] = aList[0]
# 对返回的datetime进行format %Y%m%d
item['rep_date'] = datetime.datetime.strptime(aList[1], '%Y-%m-%d %H:%M:%S').strftime('%Y%m%d')
item['rep_type'] = aList[-4]
item['rep_title'] = aList[2]
# 研报内容的链接
item['rep_link'] = "http://data.eastmoney.com/report/" + item['rep_date'] + '/sb,' + aList[8] + '.html'
item['rep_ins'] = aList[4]
item['rep_author'] = aList[-3]
# 返回内容链接的请求及将以上信息作为meta传输至parse_url
yield scrapy.Request(item['rep_link'], meta={'meta_item': item, "main_url": response.url},
callback=self.parse_url)
def parse_url(self, response):
item = response.meta['meta_item'] # 接收传输的item信息
item['rep_content'] = response.xpath('//*[@id="ContentBody"]/div/p/text()').extract()
yield item # 返回至Pipeline
yield scrapy.Request(response.meta['main_url'], callback=self.parse) # callback to crawl others
信息爬取
# 在项目根目录下执行,输出json格式信息
del sbyb.json # scrapy 默认为追加
scrapy crawl sbyb -o sbyb.json
# Crawled 3462 pages (at 1728 pages/min), scraped 3461 items (at 1735 items/min)
2 文本数据解析
2.1 词库准备
Jieba 是一个用于中文分词的Python 项目,主要实现了以下功能:
- 基于有向无环图的最大成词概率切分
- 基于 HMM 模型和 Viterbi 算法的新词发现
- 统计方法与规则相结合的,兼容ICTCLASS的词性标注
- 基于 TF-IDF 和 TextRank 的关键词提取
Jieba虽然自带了词典,但该词典基于人民日报新闻搜集整理,并不非常适合研报分词,尤其在专有名词识别上。可以考虑补金融相关的专业词库,辅以手动整理的自定义词库等。备选金融词库包括:
- 输入法词库,以搜狗、紫光、华宇等输入法为代表,均提供独立的金融词库
- 维基百科类金融词库
- 其他研究者整理的金融词库等
针对新三板特点,特补充以下词库:
-
- 个性化词库——新三板公司名称专用词
-
- 专业词库——搜狗金融词库
新三板公司专用词采用“全国中小企事业股份转让系统”中挂牌公司信息。使用scrapy进行爬取。
代码示例与说明(注释中有详细信息)
import pandas as pd
from toolkits.awful.sogouciku import GTable
from toolkits.awful.sogouciku import deal
# **********************************1 个性化词库**********************************
gongsi = pd.read_json("D:\python_workspace\crawler\\new3\gsjc.json")
user_ciku = gongsi["hqzqjc"]
user_ciku.to_csv("ciku_user.txt", encoding='utf-8', index=False)
# **********************************2 专业词库*********************************
# 将要转换的词库文件名称添加至如下列表中
o = [u'财经金融词汇大全【官方推荐】.scel', ]
for f in o:
deal(f)
# 保存结果
with open(f + '.txt', 'w') as f:
for count, py, word in GTable:
# GTable保存着结果,是一个列表,每个元素是一个元组(词频,拼音,中文词组),有需要的话可以保存成自己需要的格式
f.write(word.encode('utf-8') + '\n') # 最终保存文件的编码,可以修改
增加jieba词库
# # jieba载入词典
# 开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率。
# 用法:
jieba.load_userdict(file_name) # file_name 为自定义词典的路径。
# 词典格式和dict.txt一样,一个词占一行;每一行分三部分,一部分为词语,另一部分为词频(可省略),最后为词性(可省略),用空格隔开。
# 词频可省略,使用计算出的能保证分出该词的词频。
# 更改分词器的 tmp_dir 和 cache_file 属性,可指定缓存文件位置,用于受限的文件系统。
2.2 读取文件
def loadjsonFile(jsonFile):
df_raw = pd.read_json(jsonFile)
df = df_raw[['rep_content', 'rep_date']]
dfday = df['rep_date'].apply(lambda x: pd.to_datetime(str(x)).date()) # turn to date type
df['day'] = dfday # add a new column 'day'
df = df.set_index('day', inplace=False, drop=True)
retcontent = df.loc[df["rep_content"] != "暂无研报详细内容, 点击查看其他研报",["rep_content"]] # filter null data
retcontent.columns = [["content"]] # rename
# print sth
print "*" * 20 + "\n读入: ", retcontent.shape
print "*" * 20 + "\n数据描述: ", retcontent.describe()
return retcontent
dfcontent = loadjsonFile(u"D:\python_workspace\crawler\\new3\\new3.json")
2.3 按时间分片
def slice_df(exp1_y, exp1_m, exp1_d, exp2_y, exp2_m, exp2_d):
return dfcontent[(dfcontent.index > datetime.date(exp1_y, exp1_m, exp1_d, )) & (
dfcontent.index <= datetime.date(exp2_y, exp2_m, exp2_d))]
df_2014Q4 = slice_df(2014, 1, 1, 2014, 12, 31)
df_2015Q2 = slice_df(2014, 12, 31, 2015, 6, 30)
df_2015Q3 = slice_df(2015, 6, 30, 2015, 9, 30)
df_2015Q4 = slice_df(2015, 9, 30, 2015, 12, 31)
df_2016Q1 = slice_df(2015, 12, 31, 2016, 3, 31)
df_2016Q2 = slice_df(2016, 3, 31, 2016, 6, 30)
df_2016Q3 = slice_df(2016, 6, 30, 2016, 9, 30)
df_2016Q4 = slice_df(2016, 9, 30, 2016, 12, 31)
df_2017Q1 = slice_df(2016, 12, 31, 2017, 3, 31)
2.4 转换为词向量及进行jieba TF-IDF抽取关键词
# 分词
def convert_doc_to_wordlist(dataFrameIn, method=None):
# 分词的主要方法
dataFrame2Str = " ".join(flatten(dataFrameIn.to_string()))
if method == "textrank":
wordseg = anl.textrank(dataFrame2Str, topK=500, withWeight=True,withFlag=False)
else:
wordseg = anl.extract_tags(dataFrame2Str, topK = 500, withWeight = True)
segDict = dict(wordseg)
nonattention = [u'新三板', u'\u9884\u671f'] # 非关注词
for each in segDict.keys():
if re.search(r'\d+\.?\d*', each) or each in nonattention: # 去除数字 # 去除非关注词
segDict.pop(each)
return segDict
3 文本数据分析
3.1 对jieba抽取语料进行TF-IDF抽取关键词
# 对jieba抽取语料进行TF-IDF抽取关键词
def word_tfidf_vec(corpus):
stop_add = ["公司", "ni", "用钢", "员工", "计划", "品种", "几无", "悬念", "做市", "三板", "亿元", "成交额", "协议", "分别", "股票", "转让", "亿股",
"当日", "挂牌", "股份", "上涨", "指数", "企业", "行业", "市场", "oc", "上周"]
stopWordList=list(stopwords_all|set(stop_add))
vectorizer = CountVectorizer()
vectorizer.stop_words = stopWordList
transformer = TfidfTransformer() # 该类会统计每个词语的tf-idf权值
# 计算个词语出现的次数
X = vectorizer.fit_transform(corpus) # fit_transform是将文本转为词频矩阵
tfidf = transformer.fit_transform(X) # fit_transform是计算tf-idf
word = vectorizer.get_feature_names() # 获取词袋模型中的所有词语
weight = tfidf.toarray() # 将tf-idf矩阵抽取出来,元素a[i][j]表示j词在i类文本中的tf-idf权重
df_res = pd.DataFrame(weight.T)
df_res['word'] = word
return df_res
3.2 展示重要词及权重
r = word_tfidf_vec(corpuses)
for i in range(corpuses.__len__()):
print "****\n", i, r.sort_values(by=i, ascending=False)[:20]["word"]
4 文本数据词云
def plot_cloudMap(nWord=100):
# backgroud_Image = plt.imread("../../images/stock.jpg")
wc = WordCloud(background_color='white', # 设置背景颜色
# mask = backgroud_Image, # 设置背景图片
max_words=2000, # 设置最大现实的字数
stopwords=STOPWORDS, # 设置停用词
font_path='c:/windows/fonts/simhei.ttf', # 设置字体格式,如不设置显示不了中文
max_font_size=50, # 设置字体最大值
random_state=30, # 设置有多少种随机生成状态,即有多少种配色方案
)
res = word_tfidf_vec(corpuses)
res.columns = ["2014Q4", "2015Q2", "2015Q3", "2015Q4", "2016Q1", "2016Q2", "2016Q3", "2016Q4", "2017Q1", 'word']
for i in range(corpuses.__len__()):
print "*" * 30, res.columns[i], "\n", res.sort_values(by=res.columns[i], ascending=False)[:50]["word"]
textPlot = res.sort_values(by=res.columns[i], ascending=False)[:nWord][["word", res.columns[i]]]
textDict = textPlot.set_index('word').to_dict().values()[0]
frequencies = tuple(zip(textDict.keys(), textDict.values()))
wc.fit_words(frequencies)
# image_colors = ImageColorGenerator(backgroud_Image)
# wc.recolor(color_func = image_colors)
plt.title(res.columns[i] + u"季度关键词", fontproperties='SimHei')
plt.imshow(wc)
plt.axis('off')
plt.savefig("./outputfile//" + res.columns[i] + '.png',format="png")
# plt.show()
5 新三板市场研报文本词云展示
6 季度词云分析
如上所示词云,每个季节的关键词差异非常大,反映了市场的不同行情与阶段,同时反映了这一季度受到市场关注的一些公司、监管动向等内容。
例如,2015年Q3季度关键词之——[股市大跌 触顶 触底反弹 违纪行为 价格发现]是对“股灾”的一种反映(6月19日,上证综指重挫6.42%,创业板指数下跌5.41%,两市近千只个股跌停。)
例如,2015年Q3季度关键词之——[英派瑞 蓝贝望 天原药业 唯品会 博冠股份]是这一时期受到关注的新三板公司。
例如,2017Q1季度关键词[金丹科技],与其在1月份的出色表现相关。如下为其走势图。