果粉们忍够了!——App Store下载提速脚本

2012-04-03 21:41 by hackerzhou

首先申明一点,我不是果粉,虽然我用各种苹果产品,但是我最喜欢的手机牌子依旧是火腿肠(HTC),最喜欢的笔记本牌子依旧是ThinkPad。写本文的主要目的是方便国内使用苹果设备的同学们,想必大家都碰到过在国内下载App Store龟速的情况。价格不菲的苹果产品在天朝几Mb的带宽下竟然在以数十KB的速度下载,是相当不能忍的事情。其实原因很简单,苹果在大陆没有服务器,外国人做的软件貌似都不太了解中国国情,在这个互联网自由基本靠翻墙的神奇国度里,iTunes不增加动态检测可用的以及最快的服务器的功能真是弱爆了。不知道CEO 库克的来访是不是预示着苹果公司对中国市场越来越重视,不过国外公司无法在境内建造数据中心,必须有落地的本土企业才行,估计苹果服务器要落地内地比较难。

虽说iTunes自身不会那么智能的选择最快的接入点,但是我们可以帮它一把。网上之前也有过介绍类似PingInfoView之类批量Ping工具来找到相应最快的服务器的文章,大都hardcode了一些服务器IP,但哪些文章没有解决的就是如何得到哪些IP的,一旦苹果更改了服务器IP,那么一切都完了。所以,今天下午写了一个简单的Python脚本来动态的挑选最快的服务器。

不多说,先上代码(以下是我写的部分,没有包含我调用的Python Ping的代码,完整版请见:
https://github.com/hackerzhou/Scripts/blob/master/optimize_app_store_hosts.py
完整版脚本可以直接用(sudo) python optimize_app_store_hosts.py调用,运行完成后会在当前目录下生成两个文件,apple_ip.txt包含了App Store不同的IP地址以及各自的ping响应时间,hosts文件包含了一个自动选取ping响应最快的那个IP生成的hosts列表,大家贴到C:\Windows\system32\drivers\etc\hosts(Windows),/etc/hosts(Mac)文件中就可以了,同时也可以传到越狱了的苹果设备中去。

Note: Windows 用户执行命令python optimize_app_store_hosts.py,Mac用户执行sudo python optimize_app_store_hosts.py,因为Mac下只有root可以发出ICMP数据包。

#!/usr/bin/env python
import sys,socket

PING_TIMEOUT = 1000
def main():
  hosts = ['a%d.phobos.apple.com' % i for i in range(1, 200)]
  ips = get_ips(hosts)
  records = ping_ips(ips)
  output(records)

def get_ips(hosts):
  ips = []
  for host in hosts:
    ips.extend(get_ip(host))
  return {}.fromkeys(ips).keys()

def get_ip(host):
  print 'Getting IP for %s' % host
  ip_records = socket.getaddrinfo(host, None, socket.AF_INET)
  return [ip_record[4][0] for ip_record in ip_records]

def ping_ips(ips):
  ping_result = [(ip, my_ping(ip)) for ip in ips]
  ping_result.sort(cmp=lambda x, y: cmp(x[1], y[1]))
  return ping_result

def output(records):
  record_lines = ['IP: %s\tTime: %f ms\n' % (record[0], round(record[1])) for record in records]
  write_file('apple_ip.txt', record_lines)
  if len(records) > 0 and records[0][1] < PING_TIMEOUT:
    ip = records[0][0]
    hosts_lines = ['%s\ta%d.phobos.apple.com\n' % (ip, i) for i in range(1, 2000)]
    hosts_lines.insert(0, "#START APPLE STORE#\n")
    hosts_lines.append("#END APPLE STORE#\n")
    write_file('hosts', hosts_lines)

def write_file(filename, lines):
  with open(filename, 'w') as output_file:
    output_file.writelines(lines)
  output_file.close()

def my_ping(hostname):
  return Ping(hostname, PING_TIMEOUT, 8).run(4)

...
(Visit https://github.com/hackerzhou/Scripts/blob/master/optimize_app_store_hosts.py to see the rest part)

代码很简单,因为App Store的hostname都长成类似a1.phobos.apple.com这样,然后我们就从1到199遍历下(其实网上说可能会到2000,我实验下来大量的IP是相同的,真正不同的IP也就只有几十个。保险起见还是遍历了199个,没有验证过,如果大家有相关资料可以回复更正我。)把遍历得到的IP列表去除重复的,然后再挨个ping,最后按照ping的平均响应时间来排序,选择最快的那一个,产生一个hosts文件。本来想直接写入系统hosts文件的,因为Mac下必须用sudo才能写hosts而且随便改别人hosts文件毕竟不太好,容易引起杀毒软件报警,所以就直接写入到一个本地文件中。
Python写起来还是相当方便和简练的,特别是使用推导式构建列表以及lambda语法,用惯了Java再换用Python就会有一种耳目一新的感觉~

本文基于 署名 2.5 中国大陆 许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 hackerzhou 并包含 原文链接
发表评论

本文有 44 条评论

  1. tbwnn
    2012-05-02 16:15

    你好博主,我也做过个人博客的,用的都是美国的主机提供商,不过国内访问速度实在是不敢恭维,请问你的博客用的是什么服务器?我觉得访问速度很稳定,而且貌似还是V4 V6双栈的,能给我提供一点信息吗?谢啦~~

    • hackerzhou
      2012-05-03 21:52

      我用的是lightwave.net,其实我个人觉得速度跟自己的配置和优化很有关系

      • tbwnn
        2012-05-06 22:09

        谢谢,那你用的是什么价位的?VPS吗?

  2. 岩烧店
    2012-04-23 02:22

    hackerzhou:
    hi~

    看了你的这个网站http://love.hackerzhou.me/
    瞬间45度角了

    特地跑来真诚想求教一下网站建设的事情
    (不是为了女朋友)

    我是清华的一名八年制临床医学生,目前7年级,将毕业
    现在希望建一个关于临床医学指南的中文网站,类似wikipedia那种,专业、权威的(绝非百度百科、医学百科那类)

    这个想法诞生至今,足足1年半
    受了一群北大医学生开医疗科普网站的启发:http://www.bazhua.org
    (对于这个网站的更多评价:http://whb.news365.com.cn/jkw/201104/t20110421_3015754.htm;http://finance.ifeng.com/roll/20110421/3912655.shtml)

    关于网站内容、模式、受众等等我都想得比较清楚
    我也调研过,这个方面,市场上是空白
    关键现在对于网站建设,没有任何思路

    之所以跑来向你真诚求教,
    纯粹是热血沸腾想着创业的时候,看到校内上有人转了你的链接
    而且目前我自己人在协和(八年制就这样,2年半在清华学基础,然后5年半回协和学临床),毕竟是医学院,圈子比较小

    如果你方便且有时间,
    真诚希望能够给我一些建议!
    如果你需要更多信息,我可以通过邮件将自己网站构建的想法发给你。

    拜谢了!!!
    不胜感激!临书涕零!!!

    • 疯小晓
      2012-04-23 16:34

      你说的那个网站,一看就知道用的是wordpress模板,作者这个也是。那种网站,建设起来不难的,你可以看看我的网站http://www.liaoshixiong.com

      • hackerzhou
        2012-04-23 22:16

        没有主题是完全适合的,修改是必须的。比如我这个站点的主题就修改过后开源在https://github.com/hackerzhou/MyMinyxLITE 上。
        一个好的网站更加重要的是内容,而不是外观。
        ps:你的网站似乎是建立在免费的虚拟主机上?wordpress的配置貌似没配好,点击链接之后的域名不一致。

    • hackerzhou
      2012-04-23 22:05

      如果想做成类似wikipedia的,推荐你使用开源的wiki作为网站的基础,我曾经也搭过一个wiki:http://wiki.hackerzhou.me ,使用的是开源的MediaWiki。
      wiki的好处是可以慢慢的添加内容,直到最后变成一个专业性很强的站点。

  3. Ace
    2012-04-23 00:34

    博主你好,在校内上看到别人转载你的love story,因为我没搞过Web不懂怎么做,能否把源码给我看看?我想在GF生日的时候给她个惊喜。。

  4. DickWu
    2012-04-22 23:16

    要是ios设备上也能运行个脚本就好了~不过大前提是越狱,然而越狱后就没有必要到水果商店去下软件了。。。囧

  5. KK
    2012-04-21 21:28

    可以默默地仰望一下么……

  6. zwws
    2012-04-09 13:21

    至于覆盖 hosts 文件吗?执行完后本地的记录全没了。

  7. auess
    2012-04-08 16:48

    运行不能,文件也没有生成,报错如下:

    Getting IP for a199.phobos.apple.com

    PYTHON-PING 203.78.36.40 (203.78.36.40): 8 data bytes
    Traceback (most recent call last):
    File “optimize_app_store_hosts.py”, line 390, in
    main()
    File “optimize_app_store_hosts.py”, line 8, in main
    records = ping_ips(ips)
    File “optimize_app_store_hosts.py”, line 23, in ping_ips
    ping_result = [(ip, my_ping(ip)) for ip in ips]
    File “optimize_app_store_hosts.py”, line 43, in my_ping
    return Ping(hostname, PING_TIMEOUT, 8).run(4)
    File “optimize_app_store_hosts.py”, line 245, in run
    delay = self.do()
    File “optimize_app_store_hosts.py”, line 271, in do
    current_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname(“icmp”))
    File “/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/socket.py”, line 182, in __init__
    socket.error: [Errno 1] Operation not permitted – Note that ICMP messages can only be send from processes running as root.

    • hackerzhou
      2012-04-08 21:23

      请用sudo来执行该脚本Operation not permitted – Note that ICMP messages can only be send from processes running as root.

  8. Calaquendiv
    2012-04-08 01:05

    貌似有问题

    PYTHON-PING *.*.*.* (*.*.*.*): 8 data bytes
    Traceback (most recent call last):
    File “/Users/T******/Desktop/itunes.hosts.py”, line 390, in
    main()
    File “/Users/T******/Desktop/itunes.hosts.py”, line 8, in main
    records = ping_ips(ips)
    File “/Users/T******/Desktop/itunes.hosts.py”, line 23, in ping_ips
    ping_result = [(ip, my_ping(ip)) for ip in ips]
    File “/Users/T******/Desktop/itunes.hosts.py”, line 43, in my_ping
    return Ping(hostname, PING_TIMEOUT, 8).run(4)
    File “/Users/T******/Desktop/itunes.hosts.py”, line 245, in run
    delay = self.do()
    File “/Users/T******/Desktop/itunes.hosts.py”, line 271, in do
    current_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname(“icmp”))
    File “/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py”, line 187, in __init__
    socket.error: [Errno 1] Operation not permitted – Note that ICMP messages can only be send from processes running as root.

  9. 4hao
    2012-04-07 16:27

    弱弱的问下,这个文件是怎么使用的?

  10. zsx
    2012-04-04 12:53

    我也曾经写了一个这样的脚本,后来发现不对劲,找到的ip几乎全是日本的。事实上,你在做dns查询的时候,本身dns服务器就会根据你的ip分配给你一个比较近的ip。类似a1.phobos.apple.com只是做负载均衡用的,像从a1-a2000查出来的都是些日本的ip。只有把自己的dns服务器换成香港或台湾的,才能查到香港或台服的服务器地址。因此,你的脚本估计只能查处在日本的服务器中速度比较快的。

    • hackerzhou
      2012-04-04 14:48

      不完全是,目前我用的最快的是美帝的IP,而我查到的IP里面也很少有日本的IP。

发表评论