• R语言
  • 一个爬网页的练习:看看 R 邮件列表中最热门的讨论是什么

dapengde

以前热衷于挖坟的时候我试过,遭遇统计之都瀑布流

嗯嗯,确实是需要一些剑走偏锋的方法来挖这部分的信息。。。

Jiena

手动查了一下,cos论坛基于flarum,查了一下是有REST api来提取讨论的,地址是

https://d.cosx.org/api/discussions?page[limit]=50

试了一下每个请求最大返回50串,

这个好处是不用20串一扒减少了三分之二对cos服务器的轰炸…(28310/50=568.6)
另外代码也可以精简很多,省去rvest的操作,直接jsonlite读数据, 甚至下一页的链接也可以在api返回的links里找到

最终代码:

firsturl = "https://d.cosx.org/api/discussions?page[limit]=50" 
cos.li = list()

counter = 1
cos.li[[counter]] = jsonlite::fromJSON(firsturl)

# if the next link exists, scrape it.
while ("next" %in% names(cos.li[[counter]]$links)) {
  counter = counter +1
  cos.li[[counter]] = jsonlite::fromJSON(cos.li[[counter-1]]$links[['next']])
}

## combine all df
cos.all = do.call(rbind,
                  lapply(cos.li, function(l) {
                    df = l$data$attributes
                    df$link = paste0("https://d.cosx.org/d/", l$data$id)
                    return(df)
                  }))

不过碰到个问题,爬到“https://d.cosx.org/api/discussions?page[limit]=50?page[offset]=9550
的时候出现http 500 内部错误,浏览器直接可以打开但是R里用上面jsonlite::fromJSON的话始终会出错,好奇怪

    tctcab 试了一下,我觉得是问题来自 9550 的下下一页:

    <https://d.cosx.org/api/discussions?page%5Blimit%5D=50&page%5Boffset%5D=9650>

    浏览器打开就是错误 500。

    为了跳过这一页,我把楼上 Jiena tctcab 的方法柔在了一起:

    # get the max page (1422 pages on  2019-06-18)
    get_maxpage <- function(page_range = 1421:1500){
      for (i in page_range) {
        print(paste(Sys.time(), i))
        COS_link <- xml2::read_html(paste0('https://d.cosx.org/all?page=', i))
        url_vector= rvest::html_attr(rvest::html_nodes(COS_link, "a"), "href")
        last_link = url_vector[length(url_vector)]
        last_number <- as.numeric(gsub("[https://d.cosx.org/all?page=]", "",last_link) )
        if(last_number <= i - 1){
          message('There are ', i, ' pages with 20 posts on each.')
          return(i)
        }
      }
    }
    
    # get json from cos
    get_js <- function(url){
      print(paste(Sys.time(), url))
      mytry <- try(jsonlite::fromJSON(url))
      if(class(mytry) == 'try-error') return(NULL)
      jsonlite::fromJSON(url)
    }
    
    maxpage <- get_maxpage(1421:1500)
    cos_url <- paste0('https://d.cosx.org/api/discussions?page%5Blimit%5D=50&page%5Boffset%5D=', seq(0, maxpage * 20, 50) + 50)
    
    cos_js <- lapply(cos_url, get_js)

    可以看到, 500 错误不仅出现在读 9550 时,还出现在多处,例如 10350 和 11650,因为他们的下下一页用浏览器打开就是 500 错误:

    <https://d.cosx.org/api/discussions?page%5Blimit%5D=50&page%5Boffset%5D=10450>
    <https://d.cosx.org/api/discussions?page%5Blimit%5D=50&page%5Boffset%5D=11750>

    dapengde 这个 https 的打不开,上边 http 的可以。

    COS 的链接们打不开。

      dapengde
      继续提意见:首先我觉得三个不同页面放在不同tab下不大好,因为默认为rdev,即使只对cos感兴趣的用户,刷新一下页面就又跑去加载rdev了,还是用单独页面好一。

      其次,经常出现断开连接,在调整年限范围之后。

      再次,数据处理时间还是好慢,是不是可以考虑sql

        tctcab

        1. 你是说把他仨分成三个彼此独立的站点吗?那倒是容易,而且也快。
        2. 调整年限后断开连接的情况我还没遇见。一般情况下,用户几分钟没活动时就会自动断开,是为了节省 shinyapps.io 的机时。
        3. 确实慢,因为加载时要从 https://stat.ethz.ch/ 上读取最新的数据。等哪位把 trivis 弄好吧。此外,authors 统计数据载入得最慢,用处似乎不大,玩两天就删掉得了。

        tctcab
        嗯,好厉害,这样的确可以省很多! 太棒啦!

        dapengde
        太好啦,这样不仅可以一目了然了,而且可以用搜索栏搜感兴趣的题目了,太感谢啦!

          dapengde
          啊我以为使用的是抓取好的csv,没想到每打开一次还得在后台偷偷爬一次啊?

          甚至切换tab是不是也会重新爬?

          看你的已有代码里写的还是apply系,每次抓取可能会同时对数据源发出成百上千次访问这特喵是DDoS攻击了吧哈哈哈

            tctcab dapengde
            啊,原来是鲜榨数据呀,哈哈哈。对于 r-help 和 r-devel 可以用把历史数据存到本地,当前月份鲜榨。或者直接写是截至到某某日期的结果。 对于 COS 的话,可以先存到本地,每星期或者每月更新一次。

              tctcab Jiena

              r-devel 和 r-help 的历史数据是预先抓好的,只鲜榨最近一个月的数据。cos 目前没法鲜榨,原因是 shinyapps.io 好像不支持 jsonlite 包——这一点我没有找到依据,反正故障现象就是只要用这个包,那么布署到服务器端就出错,虽然本地运行完全没问题。

              初次切换 tab 时顿一下,并不是在重新抓取数据。可能是在渲染表格和图片吧,毕竟数据有几十万行。第二次切换就不顿了。把 COS 两万八千条文章全列在一张页面上只需几秒。

              我觉得目前速度还可以忍吧。随进度条玩一玩唐诗,经常出现惊艳的随机组合,我有时候甚至希望载入得更慢一点。

              不过,既然用户那么在乎速度,我另做了个轻便版,只载入预下载的历史数据,载入时会快一点,并且以 COS 为首页:

                dapengde

                哈哈这个好,速度满意,使用体验好很多。

                看了一下cos排名前面的帖子,要么是资料下载要么是标了“回复可见”的水贴,要筛出值得一看的帖子看来还不能依赖回复量

                  tctcab 把你发现的那些水贴用正则过滤一下,再看回复量呢?资料下载的帖子应该是很早的了