http://www.zhihu.com/people/zhang-san-12-45
# coding: utf-8
from zhihu import User
from pypinyin import pinyin, lazy_pinyin
import pypinyin
user_url = ''
user_id = ''
l = [u'bu', u'xu', u'kan']
#这里是她名字的拼音, 还是不要暴露她的好, (*/ω\*)
for num in range(100): #先在 -100以内搜索
try:
user_url = 'http://www.zhihu.com/people/bu-xu-kan-' + str(num)
user = User(user_url)
user_id = user.get_user_id()
if l != lazy_pinyin(user_id.decode('gbk')): #看看她有没有用原名
print user_id, ' ', num
except:
pass
for i in range(100):
for j in range(100): #在 -100-100以内搜索
try:
user_url = 'http://www.zhihu.com/people/bu-xu-kan-' + str(i) + '-' + str(j)
user = User(user_url)
user_id = user.get_user_id()
print user_id, ' ', i, '-', j
except:
pass
XXXXXXXX 26
XXXXXXXX 27
XXXXXXXX 42
XXXXXXXX 72
XXXXXXXX 94
she is here! 6 - 36
XXXXXXXX 6 - 76
XXXXXXXX 7 - 86
XXXXXXXX 10 - 35
XXXXXXXX 28 - 67
XXXXXXXX 32 - 28
XXXXXXXX 32 - 66
XXXXXXXX 34 - 75
彩蛋:
彩蛋已关闭,人太多,已经发不过来了- -
本机和VPS不管频率间隔多慢,仍然不断被屏蔽,粗略算了一下多出的3000人如果发完可能要到下周了,所以停掉了
骚瑞
// 代码不全,只有主要的逻辑
// 用到的库如下:
var request = require('superagent');
var cheerio = require('cheerio');
var fs = require('fs');
// 首先是这样的一个接口,可以取到某个答案所有赞同的人数
// 每次取会返回10条数据,是编译好的HTML模版,还有下一组数据的地址
// 遍历这10条数据并取到所有人的ID即可
// config 是Cookie、Host、Referer等配置
var sourceLink = 'https://www.zhihu.com/answer/' + code + '/voters_profile';
function getVoterList(link, fn) {
var next = '';
if (postListLength && !sleepIng) {
console.log('waiting');
sleepIng = true;
return setTimeout(function () {
sleepIng = false;
sleep = 1;
getVoterList(link, fn);
}, 1000 * 60);
}
request.get(link)
.set(config)
.end(function (err, res) {
if (err || !res.ok) {
return console.log(err);
}
var result = JSON.parse(res.text), voterList = '', $;
if (result.paging && result.paging.next) {
next = result.paging.next;
}
if (result.payload && result.payload.length) {
voterList = result.payload.join('');
$ = cheerio.load(voterList);
$('.zm-rich-follow-btn').each(function () {
var id = $(this).attr('data-id');
if (voterIdList.indexOf(id) === -1 && oldIdList.indexOf(id) === -1) {
console.log('new id: ', id);
voterIdList.push(id);
} else {
dupIdLen += 1;
}
});
}
if (next && dupIdLen < 20) {
setTimeout(function () {
getVoterList('https://www.zhihu.com' + next, fn);
}, 3000);
} else {
dupIdLen = 0;
fn();
}
});
}
// 在爬取完该接口后,新的点赞人数会暂存在数组中,遍历该数组,并发送请求
// 如请求发送成功,将各ID保存在某一个文件中,如发送失败,等几分钟后重试
function sendPost() {
var hasError = false;
var tempArr = [];
postListLength = voterIdList.length;
console.log('send post');
if (voterIdList.length) {
voterIdList.forEach(function (id, i) {
if (hasError) {
// 处理发送失败的情况,等待5分钟重试
if (!sleepIng) {
console.log('waiting');
sleepIng = true;
return setTimeout(function () {
sleepIng = false;
sleep = 1;
sendPost();
}, 1000 * 60 * 5);
}
return console.log('has error');
}
var index = (function () {
return i;
})(i);
var postIndex = index > postList.length ? index % postList.length : index;
setTimeout(function () {
// 一波发送完成之前不会启动下一波私信发送
postListLength--;
request.post('https://www.zhihu.com/inbox/post')
.send({
member_id: id,
content: postList[postIndex],
token: '',
_xsrf: '' // 这里是发送者的Cookie
})
.set(config)
.set({"Accept": "*/*"})
.set({"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"})
.end(function (err, res) {
console.log('hasError: ', hasError);
console.log(new Date());
console.log(res.text);
var resObj = {};
try {
resObj = JSON.parse(res.text);
} catch (e) {
console.log(e);
if (!sleepIng) {
hasError = true;
sleep = 5;
console.log('waiting');
sleepIng = true;
return setTimeout(function () {
sleepIng = false;
sleep = 1;
sendPost();
}, 1000 * 60 * 5);
}
}
if (err || !res.ok || resObj.r !== 0) {
console.log(err);
hasError = true;
sleep = 5;
tempArr = voterIdList.slice(0, index);
oldIdList = oldIdList.concat(tempArr);
fs.writeFile('./idlist.json', oldIdList, function (err) {
if (err) console.log(err);
});
}
});
}, 20 * 1000 * index * sleep);
if (index === voterIdList.length - 1) {
console.log('last');
oldIdList = oldIdList.concat(voterIdList);
voterIdList = [];
setTimeout(function () {
console.log('run again');
getVoterList(sourceLink, sendPost);
}, 1000 * 60 * 15);
fs.writeFile('./idlist.json', oldIdList, function (err) {
if (err) console.log(err);
});
console.log('done ');
}
});
} else {
setTimeout(function () {
console.log('run again');
getVoterList(sourceLink, sendPost);
}, 1000 * 60);
}
}
一个符合逻辑的思路是:我们根据关注者数据进行每日选股,一方面考虑新增的关注者数量,同时也考虑关注者的增长率,即新增关注者与总关注者的比例,对这一数值进行排序,进行每日的选股调仓。然后测试这一次选出的10个股票,看看他们这一周的表现,结果比较一般,证明舆情数据对于当日表现的作用明显,应当每日调仓。
1. 某股票昨日新增评论
2. 某股票总评论
3. 某股票昨日新增关注者
4. 某股票总关注者数目
5. 某股票卖出行为(不太准优化中)
6. 某股票买入行为(不太准优化中)
初始的10万资金在回测的结尾不到一年时间变成了118万+
当时我们真的很开心,团队大家都觉得“嗯,老板你发一个月工资给我们+这个策略我们就可以今年不要工资啦!”
雪球就可以滚起来啦...
接着有一天我们内部在讨论,假如一个并不难的“大数据爬虫”策略可以获得如此显著的Sharpe,那么为什么不会有很多基金base on舆情策略直接赚钱不就好了,来钱不是很容易吗?我们也觉得想继续深挖,那么问题来了...
后来发现,我们在回测当天调用的股票舆情数据其实是第二天早上7点才生成的,那么意味着在当天早上我们就知道了随后这一整天的股票舆情走向了!
神马?!∑q|゚Д゚|p 当时的表情是这样的...莫非注定屌丝依然是屌丝了吗!
战战兢兢地修改完代码,让舆情数据调用的API只能调用到昨天的数据,结果出来了...
年化收益率现在变成了56.7%,伴随着18%的最大回撤,只能说还行吧,虽然依然大幅度战胜了大盘!
well...还是继续回头老老实实写代码挖矿吧...可见一个圣杯不会这么容易地出现的...
巴菲特你好,巴菲特再见!
数据是非常有意思的,从中可以发现的确舆情是和股票有正相关的,而让我们设想数据爬取的速度如果达到了秒甚至毫秒级别一次更新,那么会让这个收益更加提高(我们测试了每天和几天甚至一个月的调仓效果都会比较差),是的。。。爬虫也需要更快更强
而我们想要做的更有趣的事情包括看京东、淘宝等销售数据是提前于财报发布的,并且更加真实,上面更有超过100家的上市公司在做生意,还有诸如好评的增加减少也是一个因子,敬请期待。
当大数据配合合适的工具,我们相信会有更有意思的事情发生,不过还是要提示:
股市有风险,入市需谨慎
股市有风险,入市需谨慎
股市有风险,入市需谨慎
重要的话说三遍...仅代表本人的测试看法,不代表Ricequant也不建议不理解的情况下跟随投资。
也欢迎大家关注专栏 : Money Code - http://zhuanlan.zhihu.com/ricequant
也会时不时更新有趣的策略和想法
所有的提到的数据都可以在 http://www.ricequant.com 上自己尝试,是完全免费的云端工具
写回答…