【React Native实战教程】GitHub Trending API数据的获取

项目开源地址:GitHub Popular,GitHubTrending

【React Native实战教程】GitHub Trending API数据的获取_第1张图片
React Native实战教程】GitHub Trending API数据的获取.png

关于GitHub Trending API的困惑

GitHub Popular中有个treding模块,该模块是GitHub的treding的手机版,在这个模块中你可以使用只有在PC上才能使用的功能。为了开发这个treding模块我们需要获取GitHub的treding的API数据。不过不幸的的是GitHub并没有开放有关trending的API,所以想调GitHub的treding的API已经是不现实的了。

【React Native实战教程】GitHub Trending API数据的获取_第2张图片
github.com_trending.png

拨开云雾见月明

为了给GitHub Popular的treding模块提供可靠的数据支持,我查遍了所有看似可行的方法,但都没能达到要求。本着只要思想不滑坡,方法总比问题多态度,我打开了https://github.com/trending的页面源码研究了起来。

【React Native实战教程】GitHub Trending API数据的获取_第3张图片
github.com_trending-github_popular

在源码中我发现了能够满足GitHub Popular的treding模块的所有数据,但存在如下两个问题:

  1. 冗余的数据太多,我们需要从这些冗余的数据中提取出treding模块真正需要的数据。
  2. 这些数据都是HTML格式的,而我们需要的是Json格式的数据。

GitHubTrending项目的开发

经过上述的分析,我们的需求与任务也逐渐明确了,我们需要一个能为我们提供可靠的https://github.com/trending数据的模块,暂且叫它GitHubTrending吧。这个模块需要满足如下需求:

  1. 接受一个url参数,如:https://github.com/trending/。
  2. 能够根据url参数返回对应的json或object数据。

为了实现这一需求,我们需要对请求url返回的数据进行解析,提取出我们所需要的数据,下面就跟大家分享GitHubTrending的具体实现:

数据模型TrendingRepoModel

我们需要让GitHubTrending返回一个包含TrendingRepoModel.js的集合,TrendingRepoModel.js的代码如下:

/**
 * TrendingRepoModel
 * 项目地址:https://github.com/crazycodeboy/GitHubTrending
 * 博客地址:http://www.devio.org
 * @flow
 */

export default class TrendingRepoModel {
  constructor(fullName,url,description,language,meta,contributors,contributorsUrl) {
    this.fullName = fullName;
    this.url = url;
    this.description = description;
    this.language = language;
    this.meta = meta;
    this.contributors = contributors;
    this.contributorsUrl = contributorsUrl;
  }
}

从上面代码中可以看出,TrendingRepoModel.js包含了https://github.com/trending/的所以数据的模型。

将HTML解析成TrendingRepoModel

我们通过TrendingUtil.js将HTML解析成包含TrendingRepoModel.js的集合。下面是TrendingUtil.js文件代码:

/**
 * TrendingUtil
 * 工具类:用于将github trending html 转换成 TrendingRepoModel
 * 项目地址:https://github.com/crazycodeboy/GitHubTrending
 * 博客地址:http://www.devio.org
 * @flow
 */

import TrendingRepoModel from './TrendingRepoModel';
import StringUtil from './StringUtil';

export default class TrendingUtil {
    static htmlToRepo(responseData) {
        responseData = responseData.substring(responseData.indexOf('
  • ', sliceStart); var content = htmlStr.substring(sliceStart, sliceEnd); return StringUtil.trim(content); } static parseRepoBaseInfo(repo, htmlBaseInfo) { var urlIndex = htmlBaseInfo.indexOf('', urlIndex)); repo.url = url; repo.fullName = url.slice(1, url.length); var description = this.parseContentOfNode(htmlBaseInfo, 'repo-list-description'); var index = description.indexOf(''); if (index !== -1) { var indexEmoji = description.indexOf(''); var emoji = description.substring(description.indexOf('>') + 1, indexEmoji) description = emoji + description.substring(indexEmoji + ''.length); } repo.description = description; } static parseRepoMeta(repo, htmlMeta) { var splitWit_n = htmlMeta.split('\n'); if (splitWit_n[0].search('stars') === -1) { repo.language = splitWit_n[0]; } for (var i = 0; i < splitWit_n.length; i++) { if (splitWit_n[i].search('stars') !== -1) { repo.meta = StringUtil.trim(splitWit_n[i]); break; } } } static parseRepoContributors(repo, htmlContributors) { var splitWitSemicolon = htmlContributors.split('"'); repo.contributorsUrl = splitWitSemicolon[1]; var contributors = []; for (var i = 0; i < splitWitSemicolon.length; i++) { var url = splitWitSemicolon[i]; if (url.search('http') !== -1) { contributors.push(url); } } repo.contributors = contributors; } }
  • 上面代码将HTML解析成一个包含TrendingRepoModel.js的集合,为了去除空行,上述代码中用到了StringUtil.js工具类:

    /**
     * 字符串工具类
     * 项目地址:https://github.com/crazycodeboy/GitHubTrending
     * 博客地址:http://www.devio.org
     * @flow
     */
    export default class StringUtil {
      /*
      * 去掉字符串左右空格、换行
      */
      static trim( text ){
        if (typeof(text) == "string")  {
          return text.replace(/^\s*|\s*$/g, "");
        }
        else{
          return text;
        }
      }
    }
    
    

    上述代码用于去除字符串中左右空格与换行。

    GitHubTrending封装

    经过上述步骤之后,我们的准备工作已经完成了,下面我们就可以通过GitHubTrending来提供数据了:

    /**
     * 从https://github.com/trending获取数据
     * 项目地址:https://github.com/crazycodeboy/GitHubTrending
     * 博客地址:http://www.devio.org
     * @flow
     */
    import TrendingUtil from './TrendingUtil';
    
    export default class GitHubTrending {
      GitHubTrending(){//Singleton pattern
        if (typeof GitHubTrending.instance==='object') {
          return GitHubTrending.instance;
        }
        GitHubTrending.instance=this;
      }
      fetchTrending(url){
        return new Promise((resolve,reject)=>{
          fetch(url)
          .then((response)=>response.text())
          .catch((error)=>{
            reject(error);
            console.log(error);
          }).then((responseData)=>{
            try {
              resolve(TrendingUtil.htmlToRepo(responseData));
            } catch (e) {
              reject(e);
            }
          }).done();
        });
      }
    }
    
    

    上述代码接受一个url,然后通过fetchAPI获取url返回的HTML数据,最后将HTML解析成包含TrendingRepoModel.js的集合。

    如何使用GitHubTrending

    为了方面大家使用,我已将GitHubTrending发布到npm,大家可以通过下列步骤来使用GitHubTrending。

    安装

    打开在终端中运行如下命名进行安装:

    npm i GitHubTrending --save
    

    使用

    new GitHubTrending().fetchTrending(url)
        .then((data)=> {
            //
        }).catch((error)=> {
            //
    });
    

    更多用例可参考:GitHubPopular:DataRepository.js

    总结

    从探索使用官方API,到自己动手去实现它,虽然过程比较曲折,但最终还是完成目标。经过反复测试GitHubTrending
    现在已经满足了GitHub Popular项目的需求,而且稳定性还是不错的,感兴趣的小伙伴可以下载GitHub Popular
    体验一下。

    你可能感兴趣的:(【React Native实战教程】GitHub Trending API数据的获取)