美文网首页让前端飞Web 前端开发
写个python脚本爬域名可用性

写个python脚本爬域名可用性

作者: 柳正来 | 来源:发表于2017-12-28 07:18 被阅读261次

    最近想申请个域名玩玩儿, 有不少网站提供域名检索服务, 比较有名的有godaddy, namecheap, name等. 但是想到一个搜一下太麻烦了. 有的网页做得也不是很友好, 没法指定检索自己感兴趣的顶级域名(TLD, Top Level Domain), 如.com, .io.

    发现某网站的API是直接暴露在外的, 可以直接GET到. 那索性写个脚本把自己感兴趣的都爬一下得了.

    为了保护该网站, 该API地址以API_URL指代.

    该API的设计是:

    // Request
    GET: API_URL?domain=a.com,b.io
    // Response
    {
      status: [
                { name: "a.com", available: false },
                { name: "b.io", available: true }
               ]
    }
    

    请求的domain部分是逗号分隔的域名. 返回结果我略去了其他细节, 只保留核心部分.

    代码

    代码见的Github.

    这东西其实不复杂, 不值得作为一个Repo, 更适合作为Gist. 但是Gist的版本控制感觉比较弱, 适合比较小的代码片段. 我以后也许会在现在的代码上做修改, 就还是建了个Repo.

    我的python写得很少, 可能比较蹩脚. 欢迎吐槽.

    使用

    命令行里面输入python domain-scanner.py即可.

    接受三个参数, start, endingsinterval.

    start代表你想从哪个域名开始查找, 如想从abc.com开始查找, 就--start=abc. 默认值为a.

    endings代表你感兴趣的TLD. 如你对comio感兴趣, 就--endings=com,io. 默认值为com

    interval代表间隔多久发一个请求. 如你想2秒发一次, 就--interval=2, 默认值为1.

    示例: python domain-scanner.py --start=abc --endings=com,io --interval=2.

    另外你还可以python domain-scanner.py --help查看帮助信息.

    示例:

    $ python domain-scanner.py  --start=abc --ending=com,io --interval=1
    start=abc, endings=com,io, interval=1
    from: abc, to: acp, available: []
    from: acq, to: aed, available: []
    from: aee, to: afr, available: ['aez.io', 'afq.io', 'aev.io']
    from: afs, to: ahf, available: ['afz.io', 'agq.io', 'afv.io', 'ahe.io', 'agj.io']
    from: ahg, to: ait, available: ['ahw.io', 'aij.io', 'ahz.io', 'ahj.io', 'ahy.io']
    from: aiu, to: akh, available: ['ajy.io', 'ajh.io', 'ajd.io', 'ajq.io']
    from: aki, to: alv, available: ['alh.io', 'alq.io', 'akw.io', 'akq.io', 'akz.io']
    from: alw, to: anj, available: []
    from: ank, to: aox, available: ['aor.io', 'aoq.io', 'anl.io']
    ...
    

    注:

    1. 4个字母(包含)以下的.com域名都不是available
    2. 我发现有些不available不代表被别人注册了, 也可能是你需要花大价钱出offer.

    知识点

    GET + JSON

    GET请求并把结果解析为JSON.

    from urllib.request import urlopen
    import json
    data = json.load(urlopen(url))
    

    字符串加一操作

    本代码里我只考虑英文字母的情况, 从指定的start域名开始向后遍历, 相当于26进制的数字.

    python里面字符和int之间的转换要通过chrord两个函数来做. 其中, chr的作用是, 将数字转换成字符, 如chr(97) == 'a'; ord则反过来.

    每次字符串加一都要来回来去chrord我觉得有些麻烦. 所以写了两个函数.

    def stringify(s):
        return ''.join([chr(ord("a") + ch) for ch in s])
    def codify(s):
        return [ord(ch) - ord("a") for ch in s]
    

    codify的作用是把字符串转化为数字数组(a对应0), 如codify("abc") === [0,1,2]; stringify则反过来. 这样我对数组直接进行加一操作简单一些.

    def next(a):
        carry = 1
        index = -1
        while -index <= len(a) and carry:
            a[index] += 1
            carry = a[index] // 26
            a[index] %= 26
            index -= 1
        if carry:
            a.insert(0, 0)
    

    这样, 用户输入字符串如"abc", 我就先codify[0,1,2], 然后内部都对数字数组进行next操作, 当给用户显示的时候再stringify即可.

    Python3整除

    我发现Python3里面1/2等于0.5. 默认是浮点数除法. 想整除咋办? 用a // b即可
    参考: Python integer division yields float

    Python的setInterval

    JS写多了, 发现Python居然连setInterval都没有.

    需要用threading.Timer进行一下封装.

    def setInterval(func, sec):
        def funcWrapper():
            setInterval(func, sec)
            func()
        t = threading.Timer(sec, funcWrapper)
        t.start()
        return t
    

    这只是最基础的封装, 不支持cancel. 更详细的见参考: Python Equivalent of setInterval()?

    另外, 要往调用函数里面传参咋整? 没想到好办法, 这次简单用全局变量来做的.

    Python读取命令行参数

    直接让人修改代码里面的参数再用好像太麻烦了. 开点命令行参数让用户自己设置变量吧? 怎么做?

    参考了这篇文章Command Line Arguments in Python, 不过只用到了前面的sys.argvgetopt. 刚刚发现后面还有Python3的简便argparse模块... 下次再说吧.

    简单例子如下:

    import sys, getopt
    unixOptions = "sh"  
    gnuOptions = ["start=", "help"]
    try:
        arguments, values = getopt.getopt(sys.argv[1:], unixOptions, gnuOptions)
        for arg, val in arguments:
            if arg in ("-s", "--start"):
                start = val
            elif arg in ("-h", "--help"):
                help = True
    except getopt.error as err:
        print("Failed to parse arguments.", str(err))
        sys.exit(2)
    

    其中定义了两个命令行参数starthelp, 其中, start=表示start接收参数, 而help不接收.

    Python print flush

    OK, 现在脚本支持命令行参数了, 赶紧去试试, 结果又踩坑.

    我在Sublime或者CMD里面运行脚本, print的内容都能够正常输出, 但是发现在Git Bash里面输出不出来. 查了一下, 这种情况下需要手动flush.

    两种方案:

    1. 运行脚本的时候加上-u, 如python -u domain-scanner.py.
    2. print函数调用的时候指定flush=True. 如print("yo", flush=True).

    我采用了第二种方案.

    参考: How to flush output of Python print?

    429

    发送到一段时间后, 开始有一些请求返回HTTP Error 429. 查了一下这个代表Too Many Requests. 嗯, 发得太快了. 这也是为什么加入了interval这个参数.

    目前对于失败的请求并没有失败重传, 只打印了个fail. 因为想想如果重传也一样会导致后面的请求数增多, 然后后面更加拥挤. 不如记下失败的那些, 然后之后整体重发.

    相关文章

      网友评论

        本文标题:写个python脚本爬域名可用性

        本文链接:https://www.haomeiwen.com/subject/uvfmgxtx.html