原标题:Python爬虫股票评论,snowNLP简单分析股民用户情绪
一、背景
股民是网络用户的一大群体,他们的网络情绪在一定程度上反映了该股票的情况,也反映了股市市场的波动情况。作为一只时间充裕的研究僧,我课余时间准备写个小代码get一下股民的评论数据,分析以下用户情绪的走势。代码还会修改,因为结果不准确,哈哈!
二、数据来源
本次项目不用于商用,数据来源于东方财富网,由于物理条件,我只获取了一只股票的部分评论,没有爬取官方的帖子,都是获取的散户的评论。
三、数据获取
Python是个好工具,这次我使用了selenium和PhantomJS组合进行爬取网页数据,当然还是要分析网页的dom结构拿到自己需要的数据。
爬虫部分:
fromselenium importwebdriver
importtime
importjson
importre
# from HTMLParser import HTMLParser
frommyNLP import *
# from lxml import html
# import requests
classCrawler:
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)
defcrawAllHtml( self, url) :
self.driver.get( url)
time.sleep( 2)
# htmlData = requests.get(url).content.decode('utf-8')
# domTree = html.fromstring(htmlData)
# return domTree
defgetNewUrl( self, url) :
self.newurl.add( url)
deffilterHtmlTag( self, htmlStr) :
self.htmlStr =htmlStr
#先过滤CDATA
re_cdata=re.compile( '//
[ >] ∗//
>',re.I) #匹配CDATA
re_=re.compile( ']*>[^',re.I) #
re_style=re.compile( ']*>[^',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_.sub( '',s) #去掉
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)
returns
defgetData( self) :
comments =[]
self.crawAllHtml( self.url)
postlist =self.driver.find_elements_by_xpath( '//*[@id="articlelistnew"]/div')
forpost inpostlist :
href =post.find_elements_by_tag_name( 'span')[ 2].find_elements_by_tag_name( 'a')
iflen(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])
forurl inself.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]')
iflen(post) andlen(time) andlen(age) :
text =self.filterHtmlTag(post[ 0].text)
iflen(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')
iflen(commentlist) :
forcomment incommentlist :
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]')
iflen(post) andlen(time) andlen(age) :
text =self.filterHtmlTag(post[ 0].text)
iflen(text) :
tmp =myNLP(text)
comments.append({ 'time':time[ 0].text, 'content':tmp.prob, 'age':age[ 0].text})
returnjson.dumps(comments) 存储部分:
这部分其实可以用数据库来做,但是由于只是试水,就简单用 json文件来存部分数据 importio
classFile:
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')
definputData( self, data) :
self.file.write( data.decode( 'utf-8'))
self.file.close()
defcloseFile( self) :
self.file.close() 测试用的local服务器:
这里只是为了要用浏览器浏览数据图,由于需要读取数据,js没有权限操作本地的文件,只能利用一个简单的服务器来弄了
importSimpleHTTPServer
importSocketServer;
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler);
httpd.serve_forever()NLP部分:snowNLP这个包还是用来评价买卖东西的评论比较准确
不是专门研究自然语言的,直接使用他人的算法库。这个snowNLP可以建立一个训练,有空自己来弄一个关于股票评论的。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
fromsnownlpimportSnowNLP
classmyNLP:
prob = 0.5
def_init_(self, text):
self.prob = SnowNLP(text).sentiments主调度:
# -*- coding: UTF-8 -*-
'''''
Created on 2017年5月17日
@author: luhaiya
@id: 2016110274
@deion:
'''
#http://data.eastmoney.com/stockcomment/ 所有股票的列表信息
#http://guba.eastmoney.com/list,600000,5.html 某只股票股民的帖子页面
#http://quote.eastmoney.com/sh600000.html?stype=stock 查询某只股票
fromCrawlerimport*
fromFileimport*
importsys
default_encoding = 'utf-8'
ifsys.getdefaultencoding() != default_encoding:
sys.setdefaultencoding(default_encoding)
defmain():
stocknum = str(600000)
total = dict()
foriinrange(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)
fordetailinjsonData:
num = '1'if'年'notindetail['age'].encode('utf-8')elsedetail['age'].encode('utf-8').replace('年','')
num = float(num)
date = detail['time'][4:14].encode('utf-8')
total[date] = total[date] ifdateintotal.keys()else{'num':0,'content':0}
total[date]['num'] = total[date]['num'] + numiftotal[date]['num']elsenum
total[date]['content'] = total[date]['content'] + detail['content']*numiftotal[date]['content']elsedetail['content']*num
total = json.dumps(total)
totalfile = File(stocknum,'json','./data/')
totalfile.inputData(total)
if__name__ =="__main__":
main()四、前端数据展示
使用百度的echarts。用户的情绪是使用当天所有评论的情绪值的加权平均,加权系数与用户的股龄正相关。
分析图表body{texr-align:center;}
#mainContainer{width:100%;}
#fileContainer{width:100%; text-align:center;}
#picContainer{width: 800px;height:600px;margin:0 auto;}
这里是文件夹列表