专栏首页数据派THU教你用Python爬虫股票评论,简单分析股民用户情绪

教你用Python爬虫股票评论,简单分析股民用户情绪

来源:大数据挖掘DT数据分析

本文长度为1500字,建议阅读7分钟

本文为你分享如何爬取分析股民评论数据,预测用户情绪走势。

一、背景

股民是网络用户的一大群体,他们的网络情绪在一定程度上反映了该股票的情况,也反映了股市市场的波动情况。作为一只时间充裕的研究僧,我课余时间准备写个小代码get一下股民的评论数据,分析用户情绪的走势。代码还会修改,因为结果不准确,哈哈!

二、数据来源

本次项目不用于商用,数据来源于东方财富网,由于物理条件,我只获取了一只股票的部分评论,没有爬取官方的帖子,都是获取的散户的评论。

三、数据获取

Python是个好工具,这次我使用了selenium和PhantomJS组合进行爬取网页数据,当然还是要分析网页的dom结构拿到自己需要的数据。

爬虫部分:

from selenium import webdriver  
import time  
import json  
import re    
# from HTMLParser import HTMLParser   
from myNLP import *  
# from lxml import html  
# import requests  
class Crawler:  
    url = ''  
    newurl = set()  
    headers = {}  
    cookies = {}  
    def __init__(self, stocknum, page):  
        self.url = 'http://guba.eastmoney.com/list,'+stocknum+',5_'+page+'.html'  
        cap = webdriver.DesiredCapabilities.PHANTOMJS  
        cap["phantomjs.page.settings.resourceTimeout"] = 1000  
        #cap["phantomjs.page.settings.loadImages"] = False  
        #cap["phantomjs.page.settings.localToRemoteUrlAccessEnabled"] = True  
        self.driver = webdriver.PhantomJS(desired_capabilities=cap)  
    def crawAllHtml(self,url):  
        self.driver.get(url)  
        time.sleep(2)  
#         htmlData = requests.get(url).content.decode('utf-8')  
#         domTree = html.fromstring(htmlData)  
#         return domTree  
    def getNewUrl(self,url):  
        self.newurl.add(url)  
    def filterHtmlTag(self, htmlStr):  
        self.htmlStr = htmlStr    
        #先过滤CDATA    
        re_cdata=re.compile('//<!CDATA
[>]∗//
>',re.I) #匹配CDATA    
        re_script=re.compile('<\s*script[^>]*>[^<]*<\s*/\s*script\s*>',re.I)#Script    
        re_style=re.compile('<\s*style[^>]*>[^<]*<\s*/\s*style\s*>',re.I)#style    
        re_br=re.compile('<br\s*?/?>')#处理换行    
        re_h=re.compile('</?\w+[^>]*>')#HTML标签    
        re_comment=re.compile('<!--[^>]*-->')#HTML注释    
        s=re_cdata.sub('',htmlStr)#去掉CDATA    
        s=re_script.sub('',s) #去掉SCRIPT    
        s=re_style.sub('',s)#去掉style    
        s=re_br.sub('\n',s)#将br转换为换行    
        blank_line=re.compile('\n+')#去掉多余的空行    
        s = blank_line.sub('\n',s)    
        s=re_h.sub('',s) #去掉HTML 标签    
        s=re_comment.sub('',s)#去掉HTML注释    
        #去掉多余的空行    
        blank_line=re.compile('\n+')    
        s=blank_line.sub('\n',s)    
        return s  
    def getData(self):  
        comments = []  
        self.crawAllHtml(self.url)  
        postlist = self.driver.find_elements_by_xpath('//*[@id="articlelistnew"]/div')  
        for post in postlist:  
            href = post.find_elements_by_tag_name('span')[2].find_elements_by_tag_name('a')  
            if len(href):  
                self.getNewUrl(href[0].get_attribute('href'))  
#             if len(post.find_elements_by_xpath('./span[3]/a/@href')):  
#                 self.getNewUrl('http://guba.eastmoney.com'+post.find_elements_by_xpath('./span[3]/a/@href')[0])  
        for url in self.newurl:  
            self.crawAllHtml(url)  
            time = self.driver.find_elements_by_xpath('//*[@id="zwconttb"]/div[2]')  
            post = self.driver.find_elements_by_xpath('//*[@id="zwconbody"]/div')  
            age = self.driver.find_elements_by_xpath('//*[@id="zwconttbn"]/span/span[2]')  
            if len(post) and len(time) and len(age):  
                text = self.filterHtmlTag(post[0].text)  
                if len(text):  
                    tmp = myNLP(text)  
                    comments.append({'time':time[0].text,'content':tmp.prob, 'age':age[0].text})  
            commentlist = self.driver.find_elements_by_xpath('//*[@id="zwlist"]/div')    
            if len(commentlist):  
                for comment in commentlist:  
                    time = comment.find_elements_by_xpath('./div[3]/div[1]/div[2]')  
                    post = comment.find_elements_by_xpath('./div[3]/div[1]/div[3]')  
                    age = comment.find_elements_by_xpath('./div[3]/div[1]/div[1]/span[2]/span[2]')  
                    if len(post) and len(time) and len(age):  
                        text = self.filterHtmlTag(post[0].text)  
                        if len(text):  
                            tmp = myNLP(text)  
                            comments.append({'time':time[0].text,'content':tmp.prob, 'age':age[0].text})  
        return json.dumps(comments)  

存储部分: 这部分其实可以用数据库来做,但是由于只是试水,就简单用json文件来存部分数据:

import io  
class File:  
    name = ''  
    type = ''  
    src = ''  
    file = ''  
    def __init__(self,name, type, src):  
        self.name = name  
        self.type = type  
        self.src = src    
        filename = self.src+self.name+'.'+self.type  
        self.file = io.open(filename,'w+', encoding = 'utf-8')  
    def inputData(self,data):  
        self.file.write(data.decode('utf-8'))  
        self.file.close()  
    def closeFile(self):  
        self.file.close()  

测试用的local服务器:

这里只是为了要用浏览器浏览数据图,由于需要读取数据,js没有权限操作本地的文件,只能利用一个简单的服务器来弄了:

import SimpleHTTPServer  
import SocketServer;  
PORT = 8000  
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler  
httpd = SocketServer.TCPServer(("", PORT), Handler);  
httpd.serve_forever()  

NLP部分:snowNLP这个包还是用来评价买卖东西的评论比较准确

不是专门研究自然语言的,直接使用他人的算法库。这个snowNLP可以建立一个训练,有空自己来弄一个关于股票评论的。

#!/usr/bin/env python  
# -*- coding: UTF-8 -*-  
from snownlp import SnowNLP  
class myNLP:  
    prob = 0.5  
    def _init_(self, text):  
        self.prob = SnowNLP(text).sentiments  

主调度:

# -*- coding: UTF-8 -*-  
''''' 
Created on 2017年5月17日 
@author: luhaiya 
@id: 2016110274 
@description: 
'''  
#http://data.eastmoney.com/stockcomment/  所有股票的列表信息  
#http://guba.eastmoney.com/list,600000,5.html 某只股票股民的帖子页面  
#http://quote.eastmoney.com/sh600000.html?stype=stock 查询某只股票  
from Crawler import *  
from File import *  
import sys  
default_encoding = 'utf-8'  
if sys.getdefaultencoding() != default_encoding:  
    reload(sys)  
    sys.setdefaultencoding(default_encoding)  
 
def main():  
    stocknum = str(600000)  
    total = dict()  
 for i in range(1,10):  
        page = str(i)  
        crawler = Crawler(stocknum, page)  
        datalist = crawler.getData()  
        comments = File(stocknum+'_page_'+page,'json','./data/')  
        comments.inputData(datalist)  
        data = open('./data/'+stocknum+'_page_'+page+'.json','r').read()  
        jsonData = json.loads(data)  
 for detail in jsonData:  
            num = '1' if '年' not in detail['age'].encode('utf-8') else detail['age'].encode('utf-8').replace('年','')  
            num = float(num)  
            date = detail['time'][4:14].encode('utf-8')  
            total[date] = total[date] if date in total.keys() else {'num':0, 'content':0}  
            total[date]['num'] = total[date]['num'] + num if total[date]['num'] else num  
            total[date]['content'] = total[date]['content'] + detail['content']*num if total[date]['content'] else detail['content']*num  
    total = json.dumps(total)  
    totalfile = File(stocknum,'json','./data/')  
    totalfile.inputData(total)  
if __name__ == "__main__":  
    main()  

四、前端数据展示

使用百度的echarts。用户的情绪是使用当天所有评论的情绪值的加权平均,加权系数与用户的股龄正相关。

<!DOCTYPE html>  
<html>  
<head>  
<meta charset="UTF-8">  
<title>分析图表</title>  
<style>  
body{texr-align:center;}  
#mainContainer{width:100%;}  
#fileContainer{width:100%; text-align:center;}  
#picContainer{width: 800px;height:600px;margin:0 auto;}  
</style>  
</head>  
<body>  
<div id = 'mainContainer'>  
<div id = 'fileContainer'>这里是文件夹列表</div>  
<div id = 'picContainer'></div>  
</div>  
<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>   
<script src = "./echarts.js"></script>  
<script>  
main();  
function main(){  
    var stocknum = 600000;  
    getDate(stocknum);  
}  
function getDate(stocknum){  
    var src = "./data/"+stocknum+".json";  
    $.getJSON(src, function (res){  
        var date = [];  
        for(var key in res){  
            key = key.replace('-','/').replace('-','/');  
            date.push(key);  
        }  
        date.sort();  
        data = [];  
        for (var i = 0; i < date.length; i++) {  
            dat = date[i].replace('/','-').replace('/','-');  
            data.push(res[dat]['content']/res[dat]['num']);  
        }  
        drawPic(date,data);  
    })  
}  
function drawPic(date, data){  
    //initialize and setting options  
    var myChart = echarts.init(document.getElementById('picContainer'));  
    option = {  
        tooltip: {  
            trigger: 'axis',  
            position: function (pt) {  
                return [pt[0], '10%'];  
            }  
        },  
        title: {  
            left: 'center',  
            text: '股票情绪走向图',  
        },  
        toolbox: {  
            feature: {  
                dataZoom: {  
                    yAxisIndex: 'none'  
                },  
                restore: {},  
                saveAsImage: {}  
            }  
        },  
        xAxis: {  
            type: 'category',  
            boundaryGap: false,  
            data: date  
        },  
        yAxis: {  
            type: 'value',  
            boundaryGap: [0, '100%']  
        },  
        dataZoom: [{  
            type: 'inside',  
            start: 0,  
            end: 10  
        }, {  
            start: 0,  
            end: 10,  
            handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',  
            handleSize: '80%',  
            handleStyle: {  
                color: '#fff',  
                shadowBlur: 3,  
                shadowColor: 'rgba(0, 0, 0, 0.6)',  
                shadowOffsetX: 2,  
                shadowOffsetY: 2  
            }  
        }],  
        series: [  
            {  
                name:'stocknum',  
                type:'line',  
                smooth:true,  
                symbol: 'none',  
                sampling: 'average',  
                itemStyle: {  
                    normal: {  
                        color: 'rgb(255, 70, 131)'  
                    }  
                },  
                areaStyle: {  
                    normal: {  
                        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{  
                            offset: 0,  
                            color: 'rgb(255, 158, 68)'  
                        }, {  
                            offset: 1,  
                            color: 'rgb(255, 70, 131)'  
                        }])  
                    }  
                },  
                data: data  
            }  
        ]  
    };  
    //draw pic  
    myChart.setOption(option);    
}  
</script>  
</body>  
</html>  

图1
图2

图1是我分析用户情绪画出的时间推进图,理论上小于0.5表消极情绪,大于0.5表示积极情绪。图2是实际股价的走势。

via: http://blog.csdn.net/SeaIsGod/article/details/72859071

本文分享自微信公众号 - 数据派THU(DatapiTHU)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-12-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 我是怎样爬下6万共享单车数据并进行分析的(附代码)

    来源:钱塘大数据 本文长度为3297字,建议阅读7分钟 本文为你解答用Pyhon获取、分析单车数据的过程,并为你分析得出的结论。 共享经济的浪潮席卷着各行各业,...

    数据派THU
  • 独家 | 一文读懂Hadoop(四):YARN

    随着全球经济的不断发展,大数据时代早已悄悄到来,而Hadoop又是大数据环境的基础,想入门大数据行业首先需要了解Hadoop的知识。2017年年初apache发...

    数据派THU
  • 教你用PyTorch实现“看图说话”(附代码、学习资源)

    数据派THU
  • Python爬虫股票评论,snowNLP简单分析股民用户情绪

    一、背景 股民是网络用户的一大群体,他们的网络情绪在一定程度上反映了该股票的情况,也反映了股市市场的波动情况。作为一只时间充裕的研究僧,我课余时间准备...

    机器学习AI算法工程
  • 自学Python十 爬虫实战三

      我又来送福利啦!!!不同于上篇文章,这次我们的爬虫采用了多线程,一直以来被所谓的分布式  多线程  爬虫 给唬的怕怕的。今天就来一发多线程爬虫吧,还能看妹子...

    叁金
  • Python标准库笔记(2) — re模块

    目录[-] re模块提供了一系列功能强大的正则表达式(regular expression)工具,它们允许你快速检查给定字符串是否与给定的模式匹配(matc...

    jhao104
  • 高通非adsp 架构下的sensor的bug调试

    当休眠后,再次打开preesure sensor的时候,会出现隔一段时候后,APK才会出现数据;(数据有时候会很难出现)

    233333
  • IOS 菜单栏 UITabBarController 常用

    1、创建三个视图控制器 FirstViewController、SecondViewController、ThirdViewController

    用户5760343
  • 第20天:NLP实战(四)——用GRU模型实现电影评论情感分析

      接着上次的项目,主要是为了更加熟悉我们对NLP知识的实际应用,接着上次对深度学习中的CNN的简单应用相信大家对深度学习的相关知识以及相应的实现流程有了一个更...

    stefan666
  • 微软创CoQA挑战新纪录,最接近人类水平的NLP系统诞生

    近日,微软语音与对话研究团队在斯坦福机器对话式问答数据挑战赛CoQA Challenge中夺冠,并且单模型和集成模型分别位列第二和第一,让机器阅读理解向着人类水...

    新智元

扫码关注云+社区

领取腾讯云代金券