0%

爬问财的方法

写在前面的话

i 问财 iwencai.com 是个不错的财经网站,只需要输入你所想的问句,就可以查询得到结果。这点环顾所有,貌似独此一家。

正因为它这个点,当然还有 json 的返回方式使得更容易爬,可以抓取需要的数据,而不是抓所有的。

为什么要爬

因为它方便爬,但是 baidu 搜索一轮,貌似没有人写过相关的内容,或许更多是藏私吧。

而且它想要什么就爬什么,不用再进行计算

我爬的是个股历史数据,交易和基本财务数据,除了 i 问财,暂时没有其他能这么方便

当然数据准确性也是考虑因素之一

怎么爬

简单来说,就是基于 Python + Requests

1. 怎么取得查询接口

打开 i 问财查询界面,F12 进入调试模式,可以找到数据来源在此

20190614-0

需要注意的是,它这个接口并不是不变的,2017 年至今变过几次

1
2
3
4
5
6
WENCAI_URL = {
"search1": "http://www.iwencai.com/data-robot/get-fusion-data",
"search2": "http://www.iwencai.com/data-robot/search",
"search3": "http://www.iwencai.com/stockpick/cache",
"search": "http://www.iwencai.com/stockpick/load-data"
}

最好用的,也是最初的那个接口:search2。一次查询一次返回,没有任何限制,可惜问财某次更新后就挂了。

现在用的是 search,但是使用上有需要注意的。由于我的问句是 36 columns 的表格,现在市场大概 3500 个股票,也就是返回的 json 数据是 36 X 3500。

如果直接查询,就会出错。但不是超时出错,应该是限制了返回数据文件大小,没具体考究。

我的处理方式是 p 和 perpage 进行分页获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
perpage = 1000
maxpage = 4
payload = {
"w": query,
"perpage": perpage,
"tid": "stockpick",
"queryarea": "",
"selfsectsn": "",
"querytype": "stock",
"typed": "0",
"preParams": "",
"ts": "1",
"f": "1",
"qs": "result_original",
"searchfilter": "",
#"robot": "{'source':'Ths_iwencai_Xuangu','user_id':'','log_info':'{\'other_info\':\'{\\\'eventId\\\':\\\'iwencai_pc_hp_history\\\',\\\'ct\\\':1533288325154}\'}','user_name':'','version':'1.5'}",
"p": "1"
}

payload 里面其实好多不知道什么含义,最重要的是
- w:问句内容
- perpage:分页大小
- p:页号

其他都删掉,对查询结果没什么影响

剩下的常规工作就是 concat、清洗数据、reindex

有个恶心的要处理,i 问财会在你问句返回结果硬塞 涨跌幅 最新价,需要在保存之前删除

再之前还会在最后强加一列,不过最新的查询已经没有这个痛点

还有一个恶心的,最后一个交易日数据跟前面的返回结果不一样,why?别问我,问它去!

所以按日期截取数据的话,最后交易日就需要再处理。我是懒得处理,等多一天再爬。

最后最后还是忍不住吐槽 i 问财的程序猿,别老是改接口,别老是增改字段😠

2. 序列化方式

由于我爬是为了获取历史数据,而且为了某种不知名的原因,不想用专业数据库。最终采用的是 Pickle 方式保存在本地。Pickle 也有某些痛点,在新的规划换了 HDF5,此乃后话。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CONFIG = {
"basic_dir": "%s\\basic" % DATA_DIR,
"stock_dir": "%s\\stock" % DATA_DIR,
"stock_file": "%s\\stock\\{0}.stock" % DATA_DIR,
"stock_filetype": ".stock",
"basic_file": "%s\\basic\\{0}.basic" % DATA_DIR,
"basic_filetype": ".basic",
"stats_file": "%s\\basic\\{0}.stats" % DATA_DIR,
"stats_filetype": ".stats",
"class_file": "%s\\basic\\{0}.class" % DATA_DIR,
"class_filetype": ".class",
"block_file": "%s\\basic\\{0}.block" % DATA_DIR,
"block_filetype": ".block",
"tradedate_file": "%s\\trade_date.txt" % DATA_DIR,
"all_stock_file": "%s\\stock.data" % DATA_DIR,
"all_stats_file": "%s\\stats.data" % DATA_DIR,
"all_class_file": "%s\\class.data" % DATA_DIR,
"all_block_file": "%s\\block.data" % DATA_DIR,
"render_file": "%s\\render.html" % DATA_DIR,
"output_file": "%s\\output.xlsx" % DATA_DIR}

我是按日快照方式爬,存

意思就是一个日快照数据文件 *.basic,就是一天,当天对应的数据

这里拗口的地方在于,比如说 tdx 写了一个 PB 的公式,但是它这个 PB 是根据最新的净资产来计算的

因此你翻看几年前的 PB 会出现 0.4,0.5 之类的,但实际上当时的 PB 可能是 2

这也是为什么要爬的目的,清楚数据历史变化

为了使最终前端程序快速运行,每爬一天的数据,就计算相关的

  • 统计数据 *.stats

  • 行业统计数据 *.class

  • 板块统计数据 *.block

爬完就分别整合到文件

  • stats.data

  • class.data

  • block.data

所有个股数据整合到 stock.data,然后再按股票代码切割到文件如 000001.data

3. 反爬手段

  • 修改 headers

除了 User-Agent,还给 X-Forwarded-For 生成一个随机 ip

  • Proxy 代理

如果从头开始爬,要几天时间,因为 i 问财会 ban 你的 ip

写验证代码比较麻烦

为了方便所以时不时就要切换代理

  • Selenium + Firefox webdriver

主要是为了拿 cookies 里面的 token 字

爬了干哈

数据爬下来了,目的是为了用。

因此写了一个前端 StockAnalyser,采用 pyQT + plotly