API用python搭建随机图服务,不好再加一个PHP

花享团 次浏览

摘要:网上搜了搜,其他一些文章是查询百度跳转链接,然后一个个获取真实链接,再与查询的网址进行匹配,如果能匹配上就说明已收录。我又仔细观察了一下,发现如果百度确实收录了,那么这个网址会在搜索结果的最上方,而且第一条和第二条搜索结果之间会有“以下是网页中包含……”的提示信息。

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

但是国内的API已经使用python构建了随机图服务,那为什么不再添加一个PHP呢? 算了,还不如重写一个API,于是这个项目就应运而生了。 代码已放在GitHub上,欢迎大家交流讨论。

[scode type="yellow"] 如果查询次数过于频繁,则很有可能查询失败。 目前只是半成品,只适合个人使用[/scode]

[scode type="lblue"]源码中还有其他API,可以直接看get_baidu[/scode]

Github地址

演示:api.yanshu.work/baidu/?u=https://www.sitstars.com

想法

原作者的检测方法好像是直接查询URL,然后匹配有多少个搜索结果。 如果搜索结果大于0,则认为已被收录。 然而,这种方法有一个问题。 百度有时会收录一些与目标URL无关的页面,因此检测会不准确。

网上搜索了一下,发现其他一些文章是关于查询百度跳转链接,然后一一获取真实链接,然后与查询到的URL进行匹配。 如果它们匹配,则意味着它们已被包含在内。 嗯,想法很好,理论精度很高,就是有点费时间……反正就是一个方案,我们先试试吧。

遗憾的是,由于技术有限,百度跳转后无法获取真实链接。 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  # 302
r.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)

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

分析

我只能一步步分析。 首先看一下包含的文章:

收录百度查看网站是什么_如何查看网站百度收录_收录百度查看网站的网址

看看没有包含的文章:

收录百度查看网站是什么_如何查看网站百度收录_收录百度查看网站的网址

突然我有了一个想法,我可以直接解析URL吗? 如果能匹配到,就说明已经被收录了。 如果无法匹配,则未纳入其中。 按照这个思路,很快就写出了第一个版本的代码。

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'{}'.format(url))
    result_list = pattern.findall(text)
    if result_list:
        return 200
    else:
        return 403

刚刚测试了几篇文章,确实有效,就到此为止了……等一下,我们去找别人的文章来测试一下。

进入ruanyifeng.com/blog/2017/12/blockchain-tutorial.html吧? 为什么返回403? 我在百度上搜了一下。 是的,已经收录了,而且搜索结果也是粗体的。

如何查看网站百度收录_收录百度查看网站的网址_收录百度查看网站是什么

仔细一看,哦……原来是百度隐藏了部分太长的网址,所以无法匹配。 这很难做到。 确实,我可以截取 URL 的一部分并进行匹配,但这会不准确。

我仔细一看,发现如果百度确实收录了,那么这个网址就会位于搜索结果的最前面,并且在第一次和第二次搜索之间会有提示“以下是包含...”的网页结果。 信息。 所以我有了一个新想法。 首先截取网页从开头到“以下是网页内容...”的文字,然后用正则表达式匹配百度跳转链接。 如果能够匹配,则说明百度拥有第一个搜索到的网页。 因此如何查看网站百度收录,这篇文章肯定被收录了。 所以我写了第二个版本的代码。

@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': '百度收录查询失败!'}

嗯,很好,这次我们真的可以到此为止了……(标记保留)。

PS:可以看到代码中有一个URL预处理。 这是因为如果URL没有最后一个/,将无法找到,但.html格式中不需要添加。 另外,URL开头不需要有http/https,但一定要有www如何查看网站百度收录,否则会找不到。

跨域问题

如果测试没问题,那么就可以上线,部署到服务器上,按照sitstars.com/archives/65/中的教程修改API地址,看看会发生什么。 问题又来了...

API请求地址出现亮红色,表示出现严格跨域错误。 好像是跨域错误? 我尝试使用错误消息+ fastapi 在 Google 上搜索。 果然fastapi已经考虑到了这个问题并提供了解决方案。

参考:fastapi.tiangolo.com/tutorial/cors/

简单来说,只需添加以下代码:

from fastapi import FastAPI
from 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 是所有允许的请求域的列表。 添加*表示允许所有请求。 当然,你也可以添加特定的URL和端口,例如上面的例子。

添加完后,再次测试,就显示成功了! 而且速度相当快。

百度自身的问题

正当我高兴地刷新网站查看效果时,悲剧发生了。 网页突然提示我百度收录查询失败! 为什么是这样? 我手动尝试了一下API,果然没有输出结果,但是本地使用完全没有问题。 难道是我搜索太频繁,IP被百度屏蔽了? 于是我寻找了很多解决方案,比如在 headers 中添加更多参数、更改代理 IP,但完全没有用!

无奈又看了原作者的博客,发现PHP版API的代码中有CURLOPT_FOLLOWLOCATION。 百度了一下发现它的作用就是跟随URL的重定向。 嗯……难道是服务器搜索速度太快,百度重定向没有响应? 因此,我使用第 2 节中的代码在最终跳转后打印 () URL,以查看它将我引向何处。

修改完代码后,我又重新部署了。 没想到,这次API又有用了。 这似乎是一个抽搐的问题。 刷新几次后还是不行。 这时服务器控制台上也显示了重定向的URL,和我拼接在一起的百度查询URL是一样的! 这是怎么回事? 我对互联网了解甚少,所以最终没有找到解决办法。 我只是知道了另一种判断百度查询失败的方法:只要有重定向,就一定失败了。

后记

这个东西我研究了一晚上,最后放弃了,在GitHub上留下了半成品。 我原本想部署它并提供给所有人使用,但现在我只能自己使用它。 如果您有兴趣,可以自行部署,或者留言我将您的域名添加到跨域列表中。

我接下来的计划是加个缓存,请求成功后存储在本地,一段时间内只在本地读取结果,防止每次打开文章都请求百度。

随机内容