欢迎你们订阅《Python实战-构建基于股票的量化交易系统》小册子,小册子会陆续推出与小册内容相关的专栏文章,对涉及到的知识点进行更全面的扩展介绍,而且会有选择地收录至小册中,更便于广大读者查阅知识点。本篇专栏为小册子内容的加推篇!!!html
量化交易策略的研究主要涵盖了微观和宏观这两个方面,微观方面更多地是从市场价格和成交持仓这些基础信息为研究对象,经过算法计算出技术指标,再从技术指标的变化上构建交易模型。宏观方面则是基于更多的市场资讯开发交易模型,好比从CPI、PPI、货币发行量这些宏观经济指标为研究对象构建交易模型;或者是利用数据挖掘技术重新闻事件中挖掘出可能形成市场异常波动的事件,从而得到交易的时机。正则表达式
咱们知道知名股票论坛有点金投资家园、股天下、东方财富网股吧、和讯股吧、创幻论坛、MACD股市等等,笔者用的比较多的是东方财富网股吧。在小册子中咱们以爬取东方财富网行业板块当日的行情数据为案例,介绍了网络爬虫的原理和方法,本节咱们再介绍下如何爬取东方财富网股吧帖子的内容。算法
首先经过浏览器访问伟星新材的股吧,查看该网页的URL为:http://guba.eastmoney.com/list,002372.html
,网页内容以下图所示:浏览器
当咱们点击第2页、第3页后,查看下当前的URL分别为:http://guba.eastmoney.com/list,002372_2.html
,http://guba.eastmoney.com/list,002372_3.html
,所以获得了个股股吧URL的规律为http://guba.eastmoney.com/list, 002372_%d.html
形式表示,其中的规律比较直白,%d为论坛第几页,不过这个形式是按评论时间排列的网址,若是按发帖时间的排列网址是http://guba.eastmoney.com/list,002372,f_%d.html
。bash
股吧的帖子由两部分组成,一部分为“财经评论”或“东方财富网”发布的公告或官方消息,另外一部分为散户发布的讨论帖子,以下图所示:微信
前者的帖子URL为http://guba.eastmoney.com/news,cjpl,902659513.html
,后者的帖子URL为http://guba.eastmoney.com/news,002372,902629178.html
,二者的URL均可在当前该股股吧HTML文件内容中搜寻到,以下所示:markdown
所以“财经评论”、“东方财富网”或者散户发布的帖子,主要的特征为/news,在实现上咱们能够先爬取到股吧HTML内容,而后经过正则表达式来筛选获得帖子的URL。网络
关于读取网页HTML内容的关键代码咱们已经在小册子《爬虫方式获取行业板块数据》一节中具体介绍过。须要注意的是Python2的urllib、urllib2和urlparse,已经在Python3中所有被整合到了urllib中,其中Python2的urllib和urllib2中的内容整合为urllib.request模块,urlparse整合为urllib.parse模块。 获取到HTML代码部份内容以下:函数
正则表达式筛选帖子URL,采用了re.compile和re.findall,实现代码以下,post
pattern = re.compile('/news\S+html',re.S) news_comment_urls = re.findall(pattern, html_cont.decode('utf-8')) # 非空白字符N次 """ ['/news,cjpl,902659513.html', '/news,cjpl,902684967.html', '/news,cjpl,902602349.html', '/news,cjpl,902529812.html', '/news,cjpl,857016161.html', '/news,002372,902629178.html', '/news,002372,902557935.html', '/news,002372,902533930.html', '/news,002372,902519348.html', '/news,002372,902468635.html', '/news,002372,902466626.html', '/news,002372,902464127.html', ...... '/news,002372,901168702.html', '/news,002372,901153848.html'] """ 复制代码
其中正则表达式的\S+表示匹配屡次非空白字符,而后使用findall函数找到匹配的全部字符串,并把它们做为一个列表返回。
而后是使用urljoin方法把整个url拼接好用于爬取单个帖子的标题内容,关键代码以下所示:
for comment_url in news_comment_urls : whole_url = parse.urljoin(page_url, comment_url) post_urls.add(whole_url) return post_urls 复制代码
接下来咱们把全部须要爬取的股吧页以及每页中的帖子的URL以队列的方式进行管理。Python中存储序列的类型有list、tuple、dict和set,它们之间的区别和特色简单的说:tuple不能修改其中的元素;set是无序集合,会自动去除重复元素;list是有序的集合;dict是一组key和value的组合。这次咱们选择list做为队列的存储类型。
建立target_url_manager类,该类包含如下几个方法:
add_page_urls:解析股吧单页的HTML代码,得到该页的帖子URL
add_pages_urls:构建队列,讲所有页的帖子URL创建为二维list格式
has_page_url:判断队列是否为空
get_new_url:每次推出一页的帖子URL
建立队列形式以下所示:
""" [['http://guba.eastmoney.com/news,002372,899860502.html', 'http://guba.eastmoney.com/news,002372,899832598.html', ...... 'http://guba.eastmoney.com/news,002372,899947046.html', 'http://guba.eastmoney.com/news,002372,899897958.html'], ['http://guba.eastmoney.com/news,cjpl,903685653.html', 'http://guba.eastmoney.com/news,cjpl,903679057.html', ...... 'http://guba.eastmoney.com/news,002372,901739862.html', 'http://guba.eastmoney.com/news,002372,901727241.html']] ['http://guba.eastmoney.com/news,cjpl,903685653.html', 'http://guba.eastmoney.com/news,cjpl,903679057.html', ...... 'http://guba.eastmoney.com/news,002372,901739862.html', 'http://guba.eastmoney.com/news,002372,901727241.html'] """ 复制代码
完整代码可见小册子《加推篇!爬虫抓取东方财富网股吧帖子》。
单个帖子爬取的内容包括三部分,帖子发表时间、做者及帖子标题,以下所示:
咱们能够经过正则表达式进行提取,其中在组合正则表达式时,须要考虑到HTML代码中是否有重复的匹配关键字。做者和帖子标题正则代码以下,mainbody、zwcontentmain这些关键字在文本中仅出现一次,匹配程度较高。因为网站HTML代码的改动,表达式须要常常调整。
关键代码以下所示:
com_cont = re.compile(r'<div id="mainbody">.*?zwconttbn.*?<a.*?<font>(.*?)</font>.*?<div.*?class="zwcontentmain.*?">.*?"zwconttbt">(.*?)</div>.*?social clearfix',re.DOTALL) 复制代码
发布时间正则代码以下,分两步逐渐明晰的去提取时间,因为search是扫描字符串找到这个 RE 匹配的位置,所以增长group()返回匹配字符串。
pub_elems = re.search('<div class="zwfbtime">.*?</div>',html_cont2).group() #<div class="zwfbtime">发表于 2020-02-11 09:54:48 东方财富Android版</div> pub_time = re.search('\d\d\d\d-\d\d-\d\d',pub_elems).group() #2020-02-06 复制代码
另外,论坛帖子与当前的股价走势有时间联系,太早的帖子对如今无参考做用,所以须要删选近期的帖子。咱们能够对时间进行判断,只有一个月以内发布的帖子才进行爬取并存储。获取今天的日期使用datetime.now().date(),而后与爬取的帖子时间日期比较,timedelta可在日期上作天days时间计算,但须要将时间转换为时间形式。
实现部分关键代码以下所示:
time_start=datetime.now().date() # 获取日期信息 dt = datetime.strptime(pub_time,"%Y-%m-%d") # 字符串转时间格式 datetime.date(dt)+timedelta(days=30) 复制代码
完成了单个帖子的内容爬取以后,咱们采用迭代方法把所有帖子爬取一遍。咱们经过两层迭代方法,第一层为页数,第二层为一页的股吧帖子数,将每一个帖子的URL存储在列表中,经过迭代的方式一个个爬取帖子的内容。
实现部分关键代码以下:
while self.target_page.has_page_url(): new_urls = self.target_page.get_new_url() # 获取每一个帖子的URL地址队列 for url in new_urls: …… 复制代码
当咱们爬取时发现某个帖子不存在,出现爬取信息异常时,可以使用try...except...进行异常处理。
最终爬取到的帖子内容以下图所示:
完整代码可见小册子《加推篇!爬虫抓取东方财富网股吧帖子》。
咱们能够将爬取信息写到txt文件中,打开方式的代码实现以下所示,a+为在文本尾部追加写入,而不是覆盖写入,codecs.open这个方法能够指定编码打开文件,而使用Python内置的open打开文件只能写入str类型。
f=codecs.open(name,'a+','utf-8') 复制代码
此处咱们建立一个output_txt类,该类中咱们会分别实现打开文件、写文件和关闭文件这几个方法。代码以下所示:
class output_txt(object): def open_txt(self): name = "stock_cont.txt" try: f = codecs.open(name, 'a+', 'utf-8') except Exception as e: print("NO TXT") return f def out_txt(self, f_handle, conts): try: print("cont",conts) f_handle.write(conts) except Exception as e: print("NO FILE") def close_txt(self, f_handle): f_handle.close() 复制代码
接下来就能够一边爬取帖子内容,一边把内容写入到txt文件中。实现关键代码以下所示:
file_txt = self.outputer.open_txt() while self.target_page.has_page_url(): new_urls = self.target_page.get_new_url() # 获取每一个帖子的URL地址队列 for url in new_urls: if time_start <= (self.downloader.find_time(url)+timedelta(days=30)): self.outputer.out_txt(file_txt, self.downloader.download(url)) true_time = true_time + 1 else: error_time = error_time + 1 self.outputer.close_txt(file_txt) 复制代码
写入txt文件的效果以下所示:
本小节咱们经过爬虫方式获得股吧帖子中的各类内容,那么这些内容对于咱们来讲有什么意义吗?咱们发现总有些人一直在唱空,制造恐慌的情绪,不过咱们能够经过分类分析下这些空头评论和股价的涨跌有没有什么关联,是否是有写ID是专门来唱空的呢?感兴趣的朋友们能够试试!
更多的量化交易内容欢迎你们订阅小册阅读!!同时也欢迎你们关注个人微信公众号【元宵大师带你用Python量化交易】了解更多Python量化交易相关内容