likes
comments
collection
share

如何获取在思否「问答」打卡中的完成次数?

作者站长头像
站长
· 阅读数 33
已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

最近 「SegmentFault 思否社区 10 周年「问答」打卡」 十分火热,但是有一个小问题,经常不知道是否完成今天的 KPI,以及小尾巴是否正常添加,那我们今天来做个小工具。

分析

  1. 先打开个人的问答页
  2. 查找是否有单独拉问答数据的接口。(感谢官方老板在后期做过优化,直接有接口如何获取在思否「问答」打卡中的完成次数?
  3. 右键 copy as fetch 我们就可以快乐的使用了如何获取在思否「问答」打卡中的完成次数?

改造&循环

改造成可以查出所有数据,并且过滤掉不感兴趣的信息(graphql 的就更好了,可惜不是

getAnswers = function(username, page = 1, startTime = new Date('2022-06-01 00:00:00.000').getTime() / 1000){
    return fetch(`https://segmentfault.com/gateway/homepage/${username}/answers?size=20&page=${page}&sort=newest`)
        .then(v=>v.json())
        .then(v=>v.rows)
        .then(async v=>{
            if(v.length === 20 && (v[v.length - 1]?.created || 0) > startTime){
                return v.concat(await getAnswers(username, page + 1, startTime))    
            }else{
                return v.filter(v=>v.created > startTime)
            }

        })
        // .then(console.log)
}
list = [];
getAnswers('linong')
    .then(console.log)

// new Date(1655005451 * 1000).toLocaleString();
// new Date('2022-06-01 00:00:00.000').getTime()

如何获取在思否「问答」打卡中的完成次数?

仅供学习,不要违法哟!

查看几个活跃用户

await getAnswers('hfhan')
    .then(console.log)
await getAnswers('jamesfancy')
    .then(console.log)
await getAnswers('nickw_cn')
    .then(console.log)
await getAnswers('xdsnet')
    .then(console.log)

我们会发现这里的 username 好像是一个固定值,和用户名是不一样的,那我们在做一个 url 提取,方便我们不用手动选中

'https://segmentfault.com/u/jamesfancy/answers'.match(/\/u\/([^/]+)/)[1]

如何获取在思否「问答」打卡中的完成次数?

分析如何获取是否有小尾巴

因为不是 graphql 的,所以上述内容只能有多少回答,如果想查看小尾巴的添加状况我们还需要再做一次采集。

通过查看好像也没有暴露出有接口,那我们只能直接处理 html 数据了。

xhr = new XMLHttpRequest()
xhr.open('get', 'https://segmentfault.com/q/1010000041964562/a-1020000041964682')
xhr.responseType = 'document'
xhr.send();
xhr.onload = () => console.log(xhr.response, xhr.response.querySelector('[id="1020000041964682"] [href^="https://segmentfault.com/a/1190000041925107"]'))

这样我们使用选择器直接判断回答中是否包含特征值即可,你猜为什么我这里用了 xhr,而不是 fetch 呢?

url 提取 id

'https://segmentfault.com/q/1010000041964562/a-1020000041964682'.match(/\/a-(\d+)$/)[1]

如何获取在思否「问答」打卡中的完成次数?

改造 循环

getAnswers = function(username, page = 1, startTime = new Date('2022-06-01 00:00:00.000').getTime() / 1000){
    return fetch(`https://segmentfault.com/gateway/homepage/${username}/answers?size=20&page=${page}&sort=newest`)
        .then(v=>v.json())
        .then(v=>v.rows)
        .then(async v=>{
            if(v.length === 20 && (v[v.length - 1]?.created || 0) > startTime){
                return v.concat(await getAnswers(username, page + 1, startTime))    
            }else{
                return v.filter(v=>v.created > startTime)
            }

        })
        // .then(console.log)
}
checkAnswerExt = async function(url){
    const id = url.match(/\/a-(\d+)$/)[1];
    
    var xhr = new XMLHttpRequest()
    xhr.open('get', `https://segmentfault.com${url}`)
    xhr.responseType = 'document'
    xhr.send();
    return new Promise(function(resolve, reject){
        xhr.onload = () => 
            resolve(
                xhr
               .response
               .querySelector(`[id="${id}"] [href^="https://segmentfault.com/a/1190000041925107"]`)
            )
    })
}
answers = [];
await getAnswers('cowcomic')
    .then(async function(list){
        for(var i = 0; i < list.length; i++){
            answers.push({
                answers: list[i],
                checked: await checkAnswerExt(list[i].url)
            })
        }
    })
    // .then(console.log)
answers

如何获取在思否「问答」打卡中的完成次数?

可以发现,的确是存在没有小尾巴,这样补一下即可。

分析数据

这样我们有了个人问答所有关心的数据,接下来我们可以 groupBy 查出所有没有小尾巴的数据,然后补一下数据。

也可以按时间维度查看每天完成量

大功告成。最后再提醒一居,仅供学习,不要违法哟!