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.localToRemoteUrlAccessEnabl
ed"] = 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('//]∗ //
>',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('
')#处理换行
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;
1.
2.
3. PORT = 8000
4. Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
5. httpd = SocketServer.TCPServer(("", PORT), Handler);
6. httpd.serve_forever()
NLP 部分:snowNLP 这个包还是用来评价买卖东西的评论比较准确
不是专门研究自然语言的,直接使用他人的算法库。这个 snowNLP 可以建立一
个训练,有空自己来弄一个关于股票评论的。
from snownlp import SnowNLP
1. #!/usr/bin/env python
2. # -*- coding: UTF-8 -*-
3.
4. class myNLP:
5.
prob = 0.5
6.
def _init_(self, text):
7.
self.prob = SnowNLP(text).sentiments
主调度:
1. # -*- coding: UTF-8 -*-
2.
3. Created on 2017 年 5 月 17 日
'''''
4. @author: luhaiya
5. @id: 2016110274
6. @description:
7.
8. #http://data.eastmoney.com/stockcomment/ 所有股票的列表信息
9. #http://guba.eastmoney.com/list,600000,5.html 某只股票股民的帖子页
'''
面
10.#http://quote.eastmoney.com/sh600000.html?stype=stock 查询某只股
票
reload(sys)
sys.setdefaultencoding(default_encoding)
11.from Crawler import *
12.from File import *
13.import sys
14.default_encoding = 'utf-8'
15.if sys.getdefaultencoding() != default_encoding:
16.
17.
18.
19.def main():
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
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').replac
e('年','')
32.
33.
34.
nt':0}
num = float(num)
date = detail['time'][4:14].encode('utf-8')
total[date] = total[date] if date in total.keys() else {'num':0, 'conte
35.
36.
se num
total[date]['num'] = total[date]['num'] + num if total[date]['num'] el
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)
37.
38.
39.
40.if __name__ == "__main__":
41. main()
四、前端数据展示
使用百度的 echarts。用户的情绪是使用当天所有评论的情绪值的加权平均,加
权系数与用户的股龄正相关。
1.
2.
3.
4.
5.
分析图表
6.
12.
13.
14.
18.
20.
© 2025 本站由 资料铺 提供技术支持 网站地图