本文由 发布,转载请注明出处,如有问题请联系我们! 发布时间: 2021-05-07百度收录检测API | 文章网址收录检测API接口 | 附源代码

加载中

之所以想做这个 API,主要是我博客上有百度收录检测,但是速度有点慢,后来想想可能是因为服务器在国外,所以就有了把 API 搬到国内的想法。

但是国内的 API 已经用 python 搭建了一个随机图服务,不好再加一个 PHP 吧?算了,干脆我重写一个 API 得了,于是就有了这个项目。代码已经放到 GitHub 上了,欢迎大家交流讨论。

查询次数过于频繁有大概率会查询失败,目前只是半成品,只适合自用

 

源码里有其他 API,大家直接看 `get_baidu` 即可

Github 地址

Demo:https://api.yanshu.work/baidu/?u=http://www.dkewl.com

思路

原作者检测的方法貌似是直接查询网址,然后匹配有多少搜索结果几条,如果搜索结果大于 0 就认为已收录。但是这种方法有个问题,百度有时候会收录一些与目标网址无关的页面,这样检测会不准确。

网上搜了搜,其他一些文章是查询百度跳转链接,然后一个个获取真实链接,再与查询的网址进行匹配,如果能匹配上就说明已收录。嗯想法很好,理论上准确性非常高,就是有点耗时间……不管怎么样总归是个方案,先试试。

很遗憾,技术有限,我并不能获取百度跳转后的真实链接,Stack Overflow 上给出的解决方法也统统不起作用,这个方案宣告失败。

PS:记录下获取跳转后真实链接的几种方法,说不定以后会用上。

# 方法一r = requests.get('http://techtv.mit.edu/videos/1585-music-session-02/download.source') 
print(r.url) # http://d1baxxa0joomi3.cloudfront.net/2515a9db659b0ab26d869b4ff2dadca9/original.mov# 方法二:这种适用于多次跳转response = requests.get(someurl)if response.history:
    print("Request was redirected")    for resp in response.history:
        print(resp.status_code, resp.url)
    print("Final destination:")
    print(response.status_code, response.url)else:
    print("Request was not redirected")# 方法三r = requests.get('http://github.com/', allow_redirects=False)
r.status_code  # 302r.url  # http://github.com, not https.r.headers['Location']  # https://github.com/ -- the redirect destination# 方法四import urllib.request
res = urllib.request.urlopen(starturl)
finalurl = res.geturl()
print(finalurl)

参考资料:https://stackoverflow.com/questions/20475552/python-requests-library-redirect-new-url

分析

只能一步步分析了,首先看个已收录的文章:

image.png

再看看没有收录的文章:

image.png

突然有了想法,我直接解析  <b>url<b> 不就行了?如果能匹配到就说明已收录,匹配不到就没有收录。顺着这个思路,很快写好了第一版代码。

def get_baidu(url):
    headers = {        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
    }  
    baidu = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd='
    search_url = baidu + url
    response = requests.get(search_url,headers=headers)
    text = response.text    if 'http' in url:
        url = url[url.index('//')+2:]
    pattern=re.compile(r'<b>{}</b>'.format(url))
    result_list = pattern.findall(text)    if result_list:        return 200
    else:        return 403

随便测试了几篇文章,确实有效,可以收工了……且慢,再找找其他人的文章测试一下吧。

输入 http://www.ruanyifeng.com/blog/2017/12/blockchain-tutorial.html,嗯?怎么返回 403 了?用百度搜了一下,没错啊,已经收录了,而且搜索出来的结果也是加粗的。

image.png

仔细看了一下,哦……原来百度把太长的网址隐藏了一部分啊,所以匹配不到。这就难办了,诚然我可以截取网址的一部分进行匹配,但是这样就又不精确了。

我又仔细观察了一下,发现如果百度确实收录了,那么这个网址会在搜索结果的最上方,而且第一条和第二条搜索结果之间会有“以下是网页中包含……”的提示信息。于是我有了个新的想法,首先截取网页文本从开头到“以下是网页中……”的内容,然后用正则匹配百度跳转链接,如果能匹配得到说明百度第一条有搜索到的网页结果,那这篇文章肯定收录了。于是我写出了第二版代码。

@app.get("/baidu/")async def get_baidu(u: str = Query(..., min_length=3)):
    headers = {        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',        'Referer': 'https://www.baidu.com'
    }    # 网址后缀处理
    if '.' in u[-5:]:        pass
    elif u[-1] != '/':
        u += '/'
    # 网址协议头处理
    if ('http' in u) and not ('www' in u):
        u = 'www.' + u[u.index('//')+2:]    elif ('http' not in u) and not ('www' in u):
        u = 'www.' + u

    baidu = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd='
    search_url = baidu + u    try:
        response = requests.get(search_url, headers=headers)
        text = response.text
        text = text[:text.index('以下是网页中包含')]
        pattern = re.compile(r'"http://www.baidu.com/link\?url=.+?"')
        result_list = pattern.findall(text)        if result_list:            return {'code': 200, 'msg': '该网址已被百度收录!'}        else:            return {'code': 403, 'msg': '该网址暂未被百度收录!'}    except:        return {'code': 404, 'msg': '百度收录查询失败!'}

嗯,很好,这次是真的可以收工了……(Flag 预定)。

PS:可以看到代码里有个网址的预处理,这是因为网址没有最后一个 / 时会查不出来,但是 .html 这种格式的又不需要加。另外,网址开头可以不带 http/https,但是必须带 www,要不然同样搜不出来。

跨域问题

测试没问题,那就可以上线了,部署到服务器上,按照 https://www.sitstars.com/archives/65/中的教程修改 API 地址,看下情况。问题又来了……

API 请求地址出现了一个鲜红的红色,提示 strict-origin-when-cross-origin 错误,看样子是跨域错误?试着用错误提示 +fastapi 在 Google 上搜了一下,果然 fastapi 早已经考虑到了这个问题,并且给出了解决方案。

参考资料:https://fastapi.tiangolo.com/tutorial/cors/

简单来说,加入以下代码就可以了:

from fastapi import FastAPIfrom fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [    "http://localhost.tiangolo.com",    "https://localhost.tiangolo.com",    "http://localhost",    "http://localhost:8080",    "*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

origins 是一个所有允许的请求域列表,加入 * 代表允许所有请求,当然也可以加入具体的网址和端口,比如上面几个例子。

加好后再测试一下,成功显示!而且速度还挺快。

百度自身问题

正当我开心地刷新网站看效果时,悲剧了,网页上突然提示我百度收录查询失败!这是为何?手动试了一下 API,果然输出不了结果,但是本地使用又完全没有问题。莫非是我搜得过于频繁导致 ip 被百度拉黑了?于是我找了很多种解决方案,比如 headers 添加更多参数,更换代理 ip,完全没用!

没办法我又看了原作者的博客,注意到 PHP 版本 API 的代码里有个 CURLOPT_FOLLOWLOCATION,百度一下发现它的功能是跟随网址的重定向。嗯……会不会是服务器搜索太快导致百度重定向没反应过来?于是我借助第二节的代码,print()出最终跳转后的网址,看看它到底给我定向到哪了。

修改好代码后再次部署,没想到这次 API 又有用了,看来是抽风性质的问题。刷新了几次又不能用了,而此时服务器的控制台上也刷出了重定向后的网址,和我拼接的百度查询网址一样!这又是什么情况?我自身对网络方面知之甚少,所以最终也没有解决方案,只是知道了判断百度查询失败的另一个方法:只要有重定向那就一定失败了。


评论(1条)

刀客源码 游客评论