首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >有了它,我们似乎可以告别 Stack Overflow 了?

有了它,我们似乎可以告别 Stack Overflow 了?

作者头像
崔庆才
发布2020-06-29 16:36:59
2.5K0
发布2020-06-29 16:36:59
举报
文章被收录于专栏:进击的Coder进击的Coder

先问大家一个问题,如果你撸代码的过程中遇到了一个问题不知道怎么解决,你一般会怎么办?

那当然是搜了,去哪里搜呢?

比如这里我就想知道 Python 里面怎么使用 requests 怎么上传文件,我可能就直接 Google 一下,结果有很多,比如官方文档,Stack Overflow 等等,然后一个个去查。

比如我可能就会输入关键词 python requests upload file ,查到的结果类似如下:

这里给我的第一个结果是 Stack Overflow,结果链接为 https://stackoverflow.com/questions/22567306/python-requests-file-upload,我把它点开,然后找到最高票的答案。

这里最高票的答案如图琐事,然后把它的代码 copy 下来试试看看,然后就跑通了。

不过似乎还是有一点麻烦的?开浏览器,开 Google 或 Stack Overflow,找最高票答案试试。

介绍

今天给大家介绍一个神器,叫做 howdoi,有了它,似乎我们就可以告别 Stack Overflow 了。

下面我们就先来看看 howdoi 能做点什么,安装了之后,我们就能直接输入这样的命令,比如:

howdoi python requests upload file

它给我的返回结果就是这样:

files = {'upload_file': open('file.txt','rb')}
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}

r = requests.post(url, files=files, data=values)

比如我想搜 python 怎么发送 POST 请求,输入这样的命令:

howdoi python requests post

返回结果就是这样:

>>> import requests
>>> r = requests.post('http://httpbin.org/post', json={"key": "value"})
>>> r.status_code
200
>>> r.json()
{'args': {},
 'data': '{"key": "value"}',
 'files': {},
 'form': {},
 'headers': {'Accept': '*/*',
             'Accept-Encoding': 'gzip, deflate',
             'Connection': 'close',
             'Content-Length': '16',
             'Content-Type': 'application/json',
             'Host': 'httpbin.org',
             'User-Agent': 'python-requests/2.4.3 CPython/3.4.0',
             'X-Request-Id': 'xx-xx-xx'},
 'json': {'key': 'value'},
 'origin': 'x.x.x.x',
 'url': 'http://httpbin.org/post'}

看起来还不错对不对。

比如我想搜 Python 里面怎么把 timestamp 转 datetime,输入这样的命令:

howdoi python timestamp to datetime

返回结果就是这样:

from datetime import datetime
ts = int("1284101485")

# if you encounter a "year is out of range" error the timestamp
# may be in milliseconds, try `ts /= 1000` in that case
print(datetime.utcfromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S'))

那 Java 它会吗?试试看:

howdoi java timestamp to datetime

返回结果就是这样:

Timestamp stamp = new Timestamp(System.currentTimeMillis());
Date date = new Date(stamp.getTime());
System.out.println(date);

有点牛逼啊,搜啥答案都有,准确率还蛮高。

以上是怎么实现的?没错,就是借助于 howdoi 这个项目。

howdoi

那么这个 howdoi 究竟是个什么?我们 GitHub 上就能找到,链接地址为:https://github.com/gleitz/howdoi。

看下简介:

Are you a hack programmer? Do you find yourself constantly Googling for how to do basic programming tasks? Suppose you want to know how to format a date in bash. Why open your browser and read through blogs (risking major distraction) when you can simply stay in the console and ask howdoi.

意思就是说,如果你想搜一些编程相关的解决方案,我们可以不用再去开浏览器,然后再去读文档或者博客,你可以通过 howdoi 就能直接得到答案。

操作就是上面我们讲的。

howdoi 是一个 Python 项目,我们可以 pip 命令安装:

pip3 install howdoi

如果是 Mac 的话,推荐使用 brew 来安装:

brew install howdoi

安装完了就能使用 howdoi 命令了。

完整用法如下:

usage: howdoi.py [-h] [-p POS] [-a] [-l] [-c] [-j] [-n NUM_ANSWERS] [-C] [-v] [-e ENGINE] QUERY [QUERY ...]

instant coding answers via the command line

positional arguments:
  QUERY                 the question to answer

optional arguments:
  -h, --help            show this help message and exit
  -p POS, --pos POS     select answer in specified position (default: 1)
  -a, --all             display the full text of the answer
  -l, --link            display only the answer link
  -c, --color           enable colorized output
  -j, --json-output     return answers in raw json format, to pretty print try 'howdoi pretty print json command line'
  -n NUM_ANSWERS, --num-answers NUM_ANSWERS
                        number of answers to return
  -C, --clear-cache     clear the cache
  -v, --version         displays the current version of howdoi
  -e ENGINE, --engine ENGINE  change search engine for this query only. Currently supported engines: google (default), bing, duckduckgo.

但一般来说就按照前文所演示的直接输入问题就行了。

比如看看怎样在 Python 中打印 traceback,这么搜:

howdoi print stack trace python

结果如下:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

不错不错。

原理

这时候大家可能就有疑问了,这到底是怎么实现的?为什么还能这么精准。

其实看下源码就知道了,我们稍微扒下看看,其实源码就都在这里了:https://github.com/gleitz/howdoi/blob/master/howdoi/howdoi.py。

先看看一上来定义了这么多:

SUPPORTED_SEARCH_ENGINES = ('google', 'bing', 'duckduckgo')

URL = os.getenv('HOWDOI_URL') or 'stackoverflow.com'

USER_AGENTS = ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0',
               'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100 101 Firefox/22.0',
               'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0',
               ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) '
                'Chrome/19.0.1084.46 Safari/536.5'),
               ('Mozilla/5.0 (Windows; Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46'
                'Safari/536.5'), )
SEARCH_URLS = {
    'bing': SCHEME + 'www.bing.com/search?q=site:{0}%20{1}&hl=en',
    'google': SCHEME + 'www.google.com/search?q=site:{0}%20{1}&hl=en',
    'duckduckgo': SCHEME + 'duckduckgo.com/?q=site:{0}%20{1}&t=hj&ia=web'
}

貌似我们就懂了什么,这些答案是从搜索引擎得来的。

然后我们再扒一扒,又看到一个关键的 _get_result 方法,定义如下:

def _get_result(url):
    try:
        return howdoi_session.get(url, headers={'User-Agent': _random_choice(USER_AGENTS)},
                                  proxies=get_proxies(),
                                  verify=VERIFY_SSL_CERTIFICATE).text
    except requests.exceptions.SSLError as e:
        _print_err('Encountered an SSL Error. Try using HTTP instead of '
                   'HTTPS by setting the environment variable "HOWDOI_DISABLE_SSL".\n')
        raise e

看到了吧,这里就是一次 requests 发起了 get 请求,那么这个 url 究竟是怎么来的呢?我们再顺着找下调用 _get_result 方法的地方:

def _get_links(query):
    search_engine = os.getenv('HOWDOI_SEARCH_ENGINE', 'google')
    search_url = _get_search_url(search_engine)

    result = _get_result(search_url.format(URL, url_quote(query)))
    if _is_blocked(result):
        _print_err('Unable to find an answer because the search engine temporarily blocked the request. Please wait a few minutes or select a different search engine.')
        raise BlockError("Temporary block by search engine")

    html = pq(result)
    return _extract_links(html, search_engine)

这里就是 _get_links 方法调用了 _get_result 方法,就是 search_url 的格式化结果,传入了 URL 还有 query,其中 search_url 是 _get_search_url 方法传入了 search_engine,search_engine 是通过环境变量 HOWDOI_SEARCH_ENGINE 获取的,默认是 google。

好,那顺着再看看 _get_search_url 的实现,定义如下:

def _get_search_url(search_engine):
    return SEARCH_URLS.get(search_engine, SEARCH_URLS['google'])

很明显了,就是 SEARCH_URLS 里面定义的,所以最后,我们就可以得到如下的搜索 URL:

www.google.com/search?q=site:stackoverflow.com%20{query}&hl=en

这里 query 就是我们搜索的内容,比如搜索 print stack trace python,构造的 URL 就是:

https://www.google.com/search?q=site:stackoverflow.com%20print%20stack%20trace%20python&hl=en

我们访问一下就是这样的结果:

其实这就是借助 Google 搜索了 Stack Overflow 的内容,搜索了 python 关键字的内容。

然后 howdoi 就是提取了其中的 TOP 答案,然后解析一下返回即可。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 进击的Coder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • howdoi
  • 原理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档