既然要用深度学习来做量化,那么数据是必不可少的!数据闭环也是必须的!那么爬虫就非常重要了!也许有人要质疑实时性对量化决策的影响,对不起,事实证明深度学习并不会产生高频交易!另外说一点,做量化的去年基本有一个共识就是只有高频交易能够赚钱,事实上是大错特错的!原因我后面的文章会讲到!
我们以抓取数字货币的OHLCV数据为例,我们从coinmarket网站爬取我们所需要的数据!首先我们要模拟一个浏览器操作,否则会被禁!如何做呢?
模拟一个送一个header就可以了!当然我们还需要使用代理,否则也是很容易被禁IP的!我们可以从一些代理网站上定期去爬取一些IP地址来用!接下来,我们只要使用request这个包,就可以抓取当前页面的内容,python作为胶水语言还是非常称职的!抓取到数据后,我们讲数据解析出来就可以存成一个json文件备用了!如下是部分的代码:
from enum import Enum
import os
import json
import datetime
import http
def parse_ohlcv(self, code, data):
df = pd.DataFrame()
date = {'Jan':'01',
'Feb':'02',
'Mar':'03',
'Apr':'04',
'May':'05',
'Jun':'06',
'Jul':'07',
'Aug':'08',
'Sep':'09',
'Oct':'10',
'Nov':'11',
'Dec':'12'}
q = re.compile(r's*(.*)s*(.*)s*(.*)s*(.*)s*(.*)s*.*s*.*s*')
data = q.findall(data)
for d1, d2, d3, d4, d5, d6, d7 in reversed(data):
res = re.match(r'(D+)s+(d+),s+(d+)$', d1)
d1 = res.group(3) + date[res.group(1)] + res.group(2)
if d2 == '-' or d3 == '-' or d4 == '-' or d5 == '-' or d6 == '-' or d7 == '-':
continue
edf = pd.DataFrame({'code': [code], 'date':[d1], 'open':['%.2f'%float(d2)], 'high':['%.2f'%float(d3)], 'low':['%.2f'%float(d4)], 'close':['%.2f'%float(d5)], 'volume':['%.2f'%float(d6)], 'amount':['%.2f'%float(0.0)]})
df = df.append(edf)
return df
def get_ohlcv(self, code, start, end):
url = 'https://coinmarketcap.com/currencies/{}/historical-data/?start={}&end= {}'.format(self.CryptoMapping.value[code].split(',')[1], start[:8], end[:8])
while True:
try:
if hasattr(self, 'proxy') and not len(self.proxy) == 0:
pindex = int(time.time()) % len(self.proxy)
p, p2, p3 = self.proxy['proxy'][pindex].split(':')
ip = p2 + ':' + p3
handler = rqt.ProxyHandler({p:ip})
else:
handler = rqt.HTTPHandler()
opener = rqt.build_opener(handler)
opener.addheaders = self.get_header_for_opener_method()
p = opener.open(url, timeout=20).read().decode('utf-8')
opener.close()
except err.HTTPError as e:
print('http error:', e.code, e.reason)
except err.URLError as e:
print('url error:', e.errno, e.reason)
except socket.timeout:
print('timeout error')
except (http.client.IncompleteRead, http.client.BadStatusLine, ConnectionResetError) as e:
print('IncompleteRead')
else:
break
df = parse_ohlcv(code, p)
return df
我们来细讲一下代码:
先import一些我们需要的包:
from enum import Enum
import os
import json
import datetime
import http
首先,函数接受三个参数,分别是数字货币的代码,要抓取的OHLCV的起始日期和结束日期。
def get_ohlcv(self, code, start, end):
然后我们可以找到数据页面的网址,可以用fiddler抓取到具体送出的request!
url = 'https://coinmarketcap.com/currencies/{}/historical-data/?start={}&end= {}'.format(self.CryptoMapping.value[code].split(',')[1], start[:8], end[:8])
接下来,我们查看我们的代理列表并从中随机取一个代理IP。用代理和不用代理是request handler是用的不一样的方法!
while True:
try:
if hasattr(self, 'proxy') and not len(self.proxy) == 0:
pindex = int(time.time()) % len(self.proxy)
p, p2, p3 = self.proxy['proxy'][pindex].split(':')
ip = p2 + ':' + p3
handler = rqt.ProxyHandler({p:ip})
else:
handler = rqt.HTTPHandler()
最后就是使用opener来抓取数据了,我们先要用如下方法去构造一个header。
def get_header_for_opener_method():
user_agents = [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36' 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)']
rand_index = int(time.time()) % len(user_agents)
header_tuple = [('User-Agent', user_agents[rand_index]),
('Referer', 'www.baidu.com'),
('Connection', 'keep-alive')]
return header_tuple
然后我们再抓取数据的时候注意编码方式要根据实际情况使用'utf-8'或者'CP936'等。有时候由于网络原因我们会出现timeout或者读取数据未完成的错误,所以要抛出如下几个异常,让程序继续去try!
opener = rqt.build_opener(handler)
opener.addheaders = self.get_header_for_opener_method()
p = opener.open(url, timeout=20).read().decode('utf-8')
opener.close()
基本上这就是一个爬虫的最基础的部分。接下来我们来讲一下如何来解析抓取下来的数据。
如果是json格式的数据,处理起来就非常方便,本次我们抓取到的数据是网页表格中的数据,所以需要自己手动来解析。
首先,我们实例一个dataframe用于存储我们解析好的数据。
def parse_ohlcv(self, code, data):
df = pd.DataFrame()
然后我们使用re模块来定一个正则表达式来匹配到我们需要的内容。正则表达式我们后面可以开一个专题来讲讲。这里我们只要知道s*匹配0个、1个或者多个空字符,.*表示匹配任意字符串()表示模式内存,也就是说res.group中会按顺序存储匹配到的内容。
date = {'Jan':'01',
'Feb':'02',
'Mar':'03',
'Apr':'04',
'May':'05',
'Jun':'06',
'Jul':'07',
'Aug':'08',
'Sep':'09',
'Oct':'10',
'Nov':'11',
'Dec':'12'}
q = re.compile(r's*(.*)s*(.*)s*(.*)s*(.*)s*(.*)s*.*s*.*s*')
接下来开始匹配数据,并对数据进行一些格式处理!
data = q.findall(data)
for d1, d2, d3, d4, d5, d6, d7 in reversed(data):
res = re.match(r'(D+)s+(d+),s+(d+)$', d1)
接下来将数据存储到dataframe中:
d1 = res.group(3) + date[res.group(1)] + res.group(2)
if d2 == '-' or d3 == '-' or d4 == '-' or d5 == '-' or d6 == '-' or d7 == '-':
continue
edf = pd.DataFrame({'code': [code], 'date':[d1], 'open':['%.2f'%float(d2)], 'high':['%.2f'%float(d3)], 'low':['%.2f'%float(d4)], 'close':['%.2f'%float(d5)], 'volume':['%.2f'%float(d6)], 'amount':['%.2f'%float(0.0)]})
df = df.append(edf)
return df
到这里,基本上一个爬虫的爬取数据和解析就完成了,当然其实解析html有好用的python包,为了更好的呈现过程,并没有使用!原则上我们是一定要用的,除非轮子确实不好用,我们才自力更生!
了解更多技巧,请移步我的星球:AI量化(https://t.zsxq.com/RvfY37y) 星球限时免费,如需加入,请私信我获得免费邀请码!

零基础学习Python与深度学习应用请关注星球:Python与深度学习 https://t.zsxq.com/bUFayZ3

微信公众号:QTechAI

网友评论