Python爬虫股票评论,snowNLP简单分析股民用户情绪
时间:2022-05-04
本文章向大家介绍Python爬虫股票评论,snowNLP简单分析股民用户情绪,主要内容包括一、背景、二、数据来源、三、数据获取、四、前端数据展示、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
一、背景
股民是网络用户的一大群体,他们的网络情绪在一定程度上反映了该股票的情况,也反映了股市市场的波动情况。作为一只时间充裕的研究僧,我课余时间准备写个小代码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*scripts*>',re.I)#Script
re_style=re.compile('<s*style[^>]*>[^<]*<s*/s*styles*>',re.I)#style
re_br=re.compile('<brs*?/?>')#处理换行
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
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- keras导入weights方式
- 使用Keras实现简单线性回归模型操作
- 音频处理 windows10下python三方库librosa安装教程
- Python Excel vlookup函数实现过程解析
- 浅谈Python 函数式编程
- Keras-多输入多输出实例(多任务)
- 利用Vscode进行Python开发环境配置的步骤
- python + selenium 刷B站播放量的实例代码
- 巧用x-cos-traffic-limit header来限制上传下载速率
- centos7上编译安装php7以php-fpm方式连接apache
- 基于Python实现视频的人脸融合功能
- 如何理解python对象
- Virtualenv 搭建 Py项目运行环境的教程详解
- python字符串的index和find的区别详解
- 浅谈Python 参数与变量