新三板文本项目

Posted by Big Data Memo on December 26, 2016

目录

  • 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虽然自带了词典,但该词典基于人民日报新闻搜集整理,并不非常适合研报分词,尤其在专有名词识别上。可以考虑补金融相关的专业词库,辅以手动整理的自定义词库等。备选金融词库包括:

  • 输入法词库,以搜狗、紫光、华宇等输入法为代表,均提供独立的金融词库
  • 维基百科类金融词库
  • 其他研究者整理的金融词库等

针对新三板特点,特补充以下词库:

    1. 个性化词库——新三板公司名称专用词
    1. 专业词库——搜狗金融词库

新三板公司专用词采用“全国中小企事业股份转让系统”中挂牌公司信息。使用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月份的出色表现相关。如下为其走势图。