加速github的访问与下载

本文主要是讲如何加速github访问以及下载的问题。


加速github访问

加速github访问无非就是两种办法:

  1. 搭建代理服务器;
  2. 修改hosts文件加速github访问速度
    • 推荐使用 Go 编写的 iHosts 来更新 hosts 文件 推荐

下面分别来讲这两种方法:

通过代理提供github访问速度(推荐)

2020/10/30所有通过移动网络访问github的链接都会被重置,即使设置对了ip也无法访问。

wwwechoxu

wwwechoxu

所以我只能通过搭建代理服务器来进行访问。

自建代理服务器需具备如下条件:

  • 能访问github,可在终端执行curl -I https://github.com,如果状态码是200就代表可以访问。

  • 代理服务器上额能搭建v2ray服务

我的代理服务是搭建在阿里云上,所以我本地访问github.com的链接全部走阿里云代理出去,而其它的访问链接依然用本地网络访问。

wwwechoxu

wwwechoxu

通过修改hosts文件加速github访问速度

通过修改hosts可让dns解析变得更快更干净,避免dns污染。

找出github访问慢的真正原因

有两种方法可快速找到DNS对应的ip:

  • 修改本机 Hosts 文件,主动建立域名与 IP 的映射关系,访问到这些域名时直接使用 Hosts 指定的 IP,绕过 DNS 解析。
    • 可使用ipaddress快速查找到github对应的ip,然后填写进hosts。
    • 有可能通过上面的方法查找出来的ip,我们是ping不通的(一般都是能ping通),可借助ping工具帮助我们找到真正适合我们可使用的github的ip,目前查找到的github的cdn对应的ip有如下14个,找到一个我们能ping通的且延迟不算太严重的作为hosts里填入的ip即可。

wwwechoxu

wwwechoxu

  • 修改网络的 DNS 服务器,换到能够解析出合适 IP 的 DNS 服务器,此方法是让这些DNS服务器去帮我们找到github的ip。
    • 通过dns查询工具快速找到可用的dns服务器,选择ttl值最小的,然后填写进hosts。

wwwechoxu

wwwechoxu

显然第一种方法比第二种方法更快,一般我们选择第一种方法即可。

注意

不管是第一种还是第二种一定要选择当前网络能ping通的。

需要查询如下域名:

github.com
www.github.com
github.global.ssl.fastly.net
github.map.fastly.net
github.githubassets.com
assets-cdn.github.com
documentcloud.github.com
gist.github.com
github.io
help.github.com
api.github.com
nodeload.github.com
codeload.github.com
raw.github.com
status.github.com
training.github.com
raw.githubusercontent.com
gist.githubusercontent.com
cloud.githubusercontent.com
camo.githubusercontent.com
avatars0.githubusercontent.com
avatars1.githubusercontent.com
avatars2.githubusercontent.com
avatars3.githubusercontent.com
avatars4.githubusercontent.com
avatars5.githubusercontent.com
avatars6.githubusercontent.com
avatars7.githubusercontent.com
avatars8.githubusercontent.com
github-cloud.s3.amazonaws.com
user-images.githubusercontent.com
favicons.githubusercontent.com
github-production-release-asset-2e65be.s3.amazonaws.com
github-production-user-asset-6210df.s3.amazonaws.com
github-production-repository-file-5c1aeb.s3.amazonaws.com
alive.github.com
guides.github.com
docs.github.com

以管理员身份打开cmd,输入:

notepad C:\Windows\System32\drivers\etc\hosts

新增如下内容:

# github相关域名的ip信息已于  2020-11-03 15:27:50  完成更新
140.82.114.3	github.com
140.82.114.3	www.github.com
199.232.69.194	github.global.ssl.fastly.net
199.232.68.133	github.map.fastly.net
185.199.108.154	github.githubassets.com
185.199.108.153	github.io
185.199.110.153	assets-cdn.github.com
140.82.114.3	gist.github.com
185.199.108.154	help.github.com
140.82.112.6	api.github.com
140.82.114.9	nodeload.github.com
140.82.112.10	codeload.github.com
199.232.68.133	raw.github.com
185.199.111.153	documentcloud.github.com
140.82.113.17	status.github.com
185.199.108.153	training.github.com
199.232.68.133	raw.githubusercontent.com
199.232.68.133	gist.githubusercontent.com
199.232.68.133	cloud.githubusercontent.com
199.232.68.133	camo.githubusercontent.com
199.232.68.133	avatars0.githubusercontent.com
199.232.68.133	avatars1.githubusercontent.com
199.232.68.133	avatars2.githubusercontent.com
199.232.68.133	avatars3.githubusercontent.com
199.232.68.133	avatars4.githubusercontent.com
199.232.68.133	avatars5.githubusercontent.com
199.232.68.133	avatars6.githubusercontent.com
199.232.68.133	avatars7.githubusercontent.com
199.232.68.133	avatars8.githubusercontent.com
199.232.68.133	user-images.githubusercontent.com
199.232.68.133	favicons.githubusercontent.com
52.216.128.147	github-cloud.s3.amazonaws.com
52.216.99.19	github-production-release-asset-2e65be.s3.amazonaws.com
52.216.205.67	github-production-user-asset-6210df.s3.amazonaws.com
52.217.67.196	github-production-repository-file-5c1aeb.s3.amazonaws.com
140.82.113.26	alive.github.com
185.199.110.153	guides.github.com
185.199.108.154	docs.github.com

最后使用ipconfig /flushdns刷新dns缓存。

记住: 这些ip是会变动的,如果手工填写那工作量和速度可是很慢了,所以可通过脚本来自动完成此操作。

自动更新hosts文件

每次都要去查找那么多的域名然后填写到hosts中,这些工作量其实很大的,通过脚本可帮我们完成这些。

自己写了个脚本,功能如下:

  • 自动获取ip,如果域名存在多个ip解析时,会通过ping选取平均延迟最低的ip来和域名绑定。

  • 更新hosts文件,并将原来有关github相关的配置进行替换。

下面的代码可以用来学习 Python,代码如下:

#  -*-  coding:   utf-8  -*-
#  Author  :      echoxu
#  DateTime:      2020/12/3 20:58

import re
import os
import shutil
import time
import logging
import aiohttp
import asyncio
import tldextract
from bs4 import BeautifulSoup
from pythonping import ping
import concurrent.futures

need_domains = ['github.com',
                'www.github.com',
                'github.global.ssl.fastly.net',
                'github.map.fastly.net',
                'github.githubassets.com',
                'github.io',
                'assets-cdn.github.com',
                'gist.github.com',
                'help.github.com',
                'api.github.com',
                'nodeload.github.com',
                'codeload.github.com',
                'raw.github.com',
                'documentcloud.github.com',
                'status.github.com',
                'training.github.com',
                'raw.githubusercontent.com',
                'gist.githubusercontent.com',
                'cloud.githubusercontent.com',
                'camo.githubusercontent.com',
                'avatars0.githubusercontent.com',
                'avatars1.githubusercontent.com',
                'avatars2.githubusercontent.com',
                'avatars3.githubusercontent.com',
                'avatars4.githubusercontent.com',
                'avatars5.githubusercontent.com',
                'avatars6.githubusercontent.com',
                'avatars7.githubusercontent.com',
                'avatars8.githubusercontent.com',
                'user-images.githubusercontent.com',
                'favicons.githubusercontent.com',
                'github-cloud.s3.amazonaws.com',
                'github-production-release-asset-2e65be.s3.amazonaws.com',
                'github-production-user-asset-6210df.s3.amazonaws.com',
                'github-production-repository-file-5c1aeb.s3.amazonaws.com',
                'alive.github.com',
                'guides.github.com',
                'docs.github.com'
                ]

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("获取域名对应的ip异常")


def generate_url_list():
    """ 生成符合ipadredd.com查询的url地址. """
    for domain in need_domains:
        result = tldextract.extract(domain)
        if result.registered_domain == domain:
            url = "https://{}.ipaddress.com".format(domain)
        else:
            url = "https://{}.ipaddress.com/{}".format(result.registered_domain, domain)

        url_list.append(url)


async def fetch_content(url):
    """ 爬取url,从返回的html中解析出域名对应的ip. """
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/84.0.4147.105 Safari/537.36'}

    async with aiohttp.ClientSession(
            headers=header, connector=aiohttp.TCPConnector(ssl=False)
    ) as session:
        try:
            async with session.get(url) as response:
                resp_text = await response.text()
                soup = BeautifulSoup(resp_text, 'lxml')
                ip_info_all = soup.find('tbody', id="dnsinfo").select('tr td a')
                ip_list = []

                for each_ip_all in ip_info_all:
                    ip_info = re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", each_ip_all.text)
                    if ip_info:
                        str_ip = ''.join(ip_info)
                        ip_list.append(str_ip)

                await asyncio.create_task(fetch_ip(url, ip_list))

        except Exception as e:
            logger.error(e)


async def fetch_ip(url, ip_list):
    """
    解析github相关域名的ip个数,当域名对应多个ip时进行异步操作,获取rtt最小的ip作为最终的ip.
    """
    real_url = url.split('/')[-1].replace(".ipaddress.com", "")

    if ip_list:
        if len(ip_list) == 1:
            str_ip_list = ''.join(ip_list)
            print('{} 解析到 {} 个ip,其值为 {} '.format(real_url, len(ip_list), str_ip_list))
            githubip_domain[real_url] = str_ip_list
        else:
            await asyncio.create_task(get_lowrtt_ip(url, ip_list))
    else:
        logger.error('{} 未获取到ip'.format(real_url))


def ping_ip(matched_ip):
    """ 阻塞操作,依次ping已获取ip列表里的ip并返回结果. """
    low_rtt_ip = {}

    for waitping_ip in matched_ip:
        p_r = ping(waitping_ip, timeout=1, count=5, verbose=False)
        low_rtt_ip.update({waitping_ip: p_r.rtt_avg})

    return low_rtt_ip


async def get_lowrtt_ip(url, ip_list):
    """
    利用asyncio + ThreadPoolExecutor将阻塞的操作改造成异步任务.
    """
    real_url = url.split('/')[-1].replace(".ipaddress.com", "")

    # 通过线程池将阻塞任务改造成异步任务.
    with concurrent.futures.ThreadPoolExecutor(max_workers=6) as pool:
        loop = asyncio.get_running_loop()
        ping_res = await loop.run_in_executor(pool, ping_ip, ip_list)
        # print('{} 解析到 {} 个ip,多个ip与rtt对应关系分别为: {}'.format(real_url, len(ip_list), ping_res))

    for rtt_ip, rtt_value in ping_res.items():
        if rtt_value == min(ping_res.values()):
            githubip_domain[real_url] = rtt_ip

    if real_url in githubip_domain.keys():
        print('{} 解析到 {} 个ip,最终ip(取最小rtt值)为 {} '.format(real_url, len(ip_list), githubip_domain[real_url]))


async def main(urls):
    """ 异步任务函数主入口 """
    tasks = [asyncio.create_task(fetch_content(url)) for url in urls]
    await asyncio.gather(*tasks)
    # 不加下面代码会报错: RuntimeError: Event loop is closed
    await asyncio.sleep(2)


def distinct(line):
    """ 对hosts文件去重 """
    flag = False
    for site in need_domains:
        if site in line:
            flag = flag or True
        else:
            flag = flag or False
    return flag


def update_host():
    """ 更新windows中的hosts文件 """

    print("\n正在更新系统hosts文件...请不要关闭此窗口!\n")

    today = time.strftime("%Y-%m-%d %X")
    shutil.copy("C:\\Windows\\System32\\drivers\\etc\\hosts", "C:\\Windows\\System32\\drivers\\etc\\hosts.bak")

    f1 = open("C:\\Windows\\System32\\drivers\\etc\\hosts", "r")
    lines = f1.readlines()
    f2 = open("temphost", "w")

    for line in lines:
        match_line = re.compile(r'更新').search(line)
        if not distinct(line) and not match_line:
            f2.write(line)
    f2.write("\n# github相关域名的ip信息已于  " + str(today) + "  完成更新 \n")

    for key in githubip_domain:
        f2.write(githubip_domain[key]+"\t"+key+"\n")

    f1.close()
    f2.close()

    shutil.copy("./temphost", "C:\\Windows\\System32\\drivers\\etc\\hosts")

    os.system("ipconfig /flushdns")
    print("\n已更新Github相关域名的IP信息!\n")


if __name__ == '__main__':
    start_time = time.perf_counter()
    url_list = []
    generate_url_list()
    githubip_domain = {}
    # asyncio.run(main(url_list), debug=True)
    asyncio.run(main(url_list))
    end_time = time.perf_counter()
    print('\nFetched: {}/{}(total) sites in {} seconds'.format(len(githubip_domain), len(url_list), end_time - start_time))
    update_host()

下面使用的是同步阻塞的方法:

#  -*-  coding:   utf-8  -*-
#  Author  :      EchoXuWIN
#  DateTime:      2020/11/1 15:59
#  Desc    :   获取最新的GitHub相关域名对应IP


import re
import time
import shutil
import os
import datetime
import sys
import requests
import json
import socket
import tldextract  # install tldextract
from bs4 import BeautifulSoup  # install beautifulsoup4
from pythonping import ping  # install pythonping 或者使用multi-ping


need_domains = ['github.com',
                'www.github.com',
                'github.global.ssl.fastly.net',
                'github.map.fastly.net',
                'github.githubassets.com',
                'github.io',
                'assets-cdn.github.com',
                'gist.github.com',
                'help.github.com',
                'api.github.com',
                'nodeload.github.com',
                'codeload.github.com',
                'raw.github.com',
                'documentcloud.github.com',
                'status.github.com',
                'training.github.com',
                'raw.githubusercontent.com',
                'gist.githubusercontent.com',
                'cloud.githubusercontent.com',
                'camo.githubusercontent.com',
                'avatars0.githubusercontent.com',
                'avatars1.githubusercontent.com',
                'avatars2.githubusercontent.com',
                'avatars3.githubusercontent.com',
                'avatars4.githubusercontent.com',
                'avatars5.githubusercontent.com',
                'avatars6.githubusercontent.com',
                'avatars7.githubusercontent.com',
                'avatars8.githubusercontent.com',
                'user-images.githubusercontent.com',
                'favicons.githubusercontent.com',
                'github-cloud.s3.amazonaws.com',
                'github-production-release-asset-2e65be.s3.amazonaws.com',
                'github-production-user-asset-6210df.s3.amazonaws.com',
                'github-production-repository-file-5c1aeb.s3.amazonaws.com',
                'alive.github.com',
                'guides.github.com',
                'docs.github.com'
                ]


ip_domain = {}


# 利用ipaddress.com查找ip,也可用http://ip.tool.chinaz.com/ + domain查找
def ipaddress_output_hosts(domain):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'}
    result = tldextract.extract(domain)
    # 如果是一级域名(github.com)这样的,就拼接为https://{domain}.ipaddress.com
    # 否则就拼接成https://{result.registered_domain}.ipaddress.com/{domain}
    if result.registered_domain == domain:
        url = "https://{}.ipaddress.com".format(domain)
    else:
        url = "https://{}.ipaddress.com/{}".format(result.registered_domain, domain)

    resp = requests.get(url=url, headers=headers)
    real_ip = None
    try:
        soup = BeautifulSoup(resp.text, 'lxml')
        # 其实最精准的ip数据应该从'table[panel-item table table-border-row table-v faq]'下查找内容匹配
        # 'What IP address does 查询的域名 resolve to?'这样格式的'h3'标签
        # 从DNS Resource Records中也可找到
        has_ip_table = soup.select('#map-1 + table[class="panel-item table table-stripes table-v"]')[0]
        ips = has_ip_table.select('tr')[-1].select('td ul li')
        if len(ips) == 1:
            real_ip = ips[0].text
        else:
            low_ttl_ip = {}
            for ip in ips:
                # TODO 使用多线程加速完成ping的过程
                p_r = ping(ip.text, timeout=1, count=5, verbose=False)
                # 构造一个包含{ip地址:响应时间}的字典
                low_ttl_ip.update({ip.text: p_r.rtt_avg})
            # 将平均延迟最小的ip与域名绑定并添加到字典中
            for ttl_ip, ttl_value in low_ttl_ip.items():
                if ttl_value == min(low_ttl_ip.values()):
                    real_ip = ttl_ip
    except Exception as e:
        print(e)
    return real_ip


# 在ip_domain中存储ip:域名的对应关系
def generate_dict():
    for site_name in need_domains:
        site_ip = ipaddress_output_hosts(site_name)
        if site_ip:
            ip_domain[site_name] = site_ip
            print(site_ip + "\t" + site_name)
        else:
            print("# {} 没有找到IP。".format(site_name))


# 对hosts文件去重
def distinct(line):
    flag = False
    for site in need_domains:
        if site in line:
            flag = flag or True
        else:
            flag = flag or False
    return flag


# 更新hosts文件
# TODO 生成switchosts远程文件
def update_host():
    print("\n内容生成中,请耐心等待...请不要关闭此窗口!\n")
    generate_dict()
    today = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    shutil.copy("C:\\Windows\\System32\\drivers\\etc\\hosts", "C:\\Windows\\System32\\drivers\\etc\\hosts.bak")
    f1 = open("C:\\Windows\\System32\\drivers\\etc\\hosts", "r")
    lines = f1.readlines()
    f2 = open("temphost", "w")
    # 为了防止host越写用越长,需要删除之前更新的含有github相关内容
    for line in lines:
        match_line = re.compile(r'更新').search(line)
        if not distinct(line) and not match_line:
            f2.write(line)
    f2.write("# github相关域名的ip信息已于  " + str(today) + "  完成更新 \n")
    for key in ip_domain:
        f2.write(ip_domain[key]+"\t"+key+"\n")
    f1.close()
    f2.close()
    # 覆盖原来的host
    shutil.copy("./temphost", "C:\\Windows\\System32\\drivers\\etc\\hosts")

    os.system("ipconfig /flushdns")
    print("\n已更新Github相关域名的IP信息!\n")


if __name__ == '__main__':
    start_time = time.perf_counter()
    update_host()
    end_time = time.perf_counter()
    print(end_time - start_time)

wwwechoxu

wwwechoxu

使用switchhosts进行自动更新hosts

我们写完脚本以后放到服务器上,写个计划任务每隔一小时跑脚本生成文件(上面的代码需要改下)。

然后本机可通过SwitchHosts进行自动更新。

注意

这里获取的ip不一定是最适合你本地环境的,因为服务器的网络环境和我们本地的网络环境不一样。

有可能出现服务器上可以访问到的ip而在我们本地不能访问。

当然我们也可使用别人已经写好的。

https://gitee.com/xueweihan/codes/6g793pm2k1hacwfbyesl464/raw?blob_name=GitHub520.yml填入remote的url中并设置每隔1小时进行更新

SwitchHosts

switchhosts自动更新hosts

wwwechoxu

wwwechoxu

加速github下载

因为一些原因导致下载github上的文件会很慢,现在可通过如下方法加速下载github上的文件。

码云GitHub镜像站

当我们获取了github的下载链接后,我们可通过国内的代码平台对我们需要下载的文件进行镜像。

wwwechoxu

然后填上从github上复制的下载链接url即可加速下载。

需要注意:

1.这个镜像站点不是所有的github项目,不过大多数热门项目都会有

2.issue和release包也没有,只有代码

3.有一天的延迟。即你看到的是一天前的项目状态

4.因为不是github,所以你也没法通过这个push到github上的项目

GitHub镜像站

通过github.com.cnpmjs.org/这个镜像站进行下载。

使用方法就是将github.com改为github.com.cnpmjs.org

如下:

git clone https://github.com/kubernetes/kubernetes.git

===> git clone https://github.com.cnpmjs.org/kubernetes/kubernetes.git

注意

一定不要在这个网站上登录账户,当然也可通过油猴脚本进行自动替换。

GitClone站点

通过gitclone站点进行加速下载:

方法一(替换URL)

git clone https://gitclone.com/github.com/tendermint/tendermint.git

方法二(设置git参数)

git config --global url."https://gitclone.com/".insteadOf https://

git clone https://github.com/tendermint/tendermint.git

方法三(使用cgit客户端)

cgit clone https://github.com/tendermint/tendermint.git

使用浏览器插件或者脚本进行加速下载

此方法的好处是自动在github的下载界面新增"快速下载"等按钮,而这些按钮会自动完成如上的镜像站的域名修改等工作。

下面是一些常见的加速脚本或者插件:

谷歌浏览器GitHub加速插件

wwwechoxu

下面的两个都是油猴github加速脚本,功能差不多,选其一:

油猴github加速脚本

油猴github加速脚本1

wwwechoxu

wwwechoxu

wwwechoxu

上次更新:
贡献者: iEchoxu