Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
在這篇文章/教程中,我們將使用 NodeJS 創建一個 API 代理服務器,這背后的主要原因是向您展示如何隱藏公共 API 密鑰,而不是像我過去那樣公開它們。我們所有人都創建了一個應用程序,只是為了了解一個新的庫或框架,而實現這一點的最佳方法是使用開放 API(如TMDB)。
這些開放 API 中的大多數都需要在發出請求之前在請求 URL 或標頭中添加 API 密鑰。無論哪種方式,API 密鑰都可能被實際上不擁有此密鑰的人竊取和使用。因此,您最終可能會被暫停帳戶,或者您的應用程序無法按預期運行。
請記住:API 密鑰屬于應用程序的服務器端。
話不多說,讓我們創建這個 API 代理服務器。為了這篇文章/教程的緣故,我們將使用Wea?ther API。
在開始編碼之前,我們需要具備以下條件:
創建應用程序的項目文件夾
殼
cd ~/Documents/tutorials
mkdir api-proxy-server && cd api-proxy-server
npm init -y
安裝所需的 NPM 包
npm install -S express cors dotenv axios
npm install -D nodemon # for faster development
在 package.json 文件中準備腳本
JSON
{
"scripts": {
"start": "node index.js",
"dev": "nodemon --config nodemon.json"
}
}
讓我們看一下項目的文件夾和文件,以便更清晰地了解結構。
server/
├── src
│ ├── utils
│ │ └── env.js
│ └── routes
│ └── index.js
├── package.json
├── nodemon.json
├── index.js
└── .env
3 directories, 6 files
在項目的根目錄下創建一個index.js和一個文件。nodemon.json
JSON
// nodemon.json
{
"verbose": true,
"ignore": ["node_modules/"],
"watch": ["./**/*"]
}
在我們開始編輯 entry ( index.js) 文件之前,我們需要創建另外兩個有用的文件。第一個是.env我們所有環境變量所在的文件。它將有點可重用,以便能夠與除 OpenWeatherMap API 之外的其他公共 API 一起使用。
API_PORT = 1337
API_BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
API_KEY = "1d084c18063128c282ee3b41e91b6740" # not actually api key; use a valid one
另一個文件是src/utils/env.js負責讀取和導出所有環境變量的文件。
JavaScript
require("dotenv").config();
module.exports = {
port: Number(process.env.API_PORT) || 3000,
baseURL: String(process.env.API_BASE_URL) || "",
apiKey: String(process.env.API_KEY) || "",
};
現在是時候編輯主文件并向這個代理服務器應用程序添加一些邏輯了。
JavaScript
// imports
const express = require("express");
const cors = require("cors");
const env = require("./src/utils/env");
// Application
const app = express();
// Middlewares
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
// Routes
app.use("/api", require("./src/routes")); // Every request that starts with /api will be handled by this handler
// This route will handle all the requests that are not handled by any other route handler
app.all("*", (request, response, next) => {
return response.status(404).json({ message: "Endpoint not found!" });
});
// Bootstrap server
app.listen(env.port, () => {
console.log(`Server is up and running at http://localhost:${env.port}`);
});
這里的事情很簡單;它是一個基本的 ExpressJs 服務器應用程序。在頂部,我們有所需的導入。然后我們有一些需要的中間件,例如JSON中間件,它負責解析帶有 JSON 有效負載的傳入請求,并且基于body-parser. 接下來,我們在此處管理端點及其處理程序的路由。最后,我們得到了服務器的引導。
讓我們看一下/api路由的處理程序。
JavaScript
// server/src/routes/index.js
const router = require("express").Router();
const { default: axios } = require("axios");
const env = require("../utils/env");
// [GET] Current weather data
router.get("/", async (request, response, next) => {
try {
const query = request.query || {};
const params = {
appid: env.apiKey, // required field
...query,
};
const { data } = await axios.get(env.baseURL, { params });
return response.status(200).json({
message: "Current weather data fetched!",
details: { ...data },
});
} catch (error) {
const {
response: { data },
} = error;
const statusCode = Number(data.cod) || 400;
return response
.status(statusCode)
.json({ message: "Bad Request", details: { ...data } });
}
});
module.exports = router;
請求處理函數將GET我們在調用它時提供的查詢字段作為輸入。
例如,如果我們沒有這個 API 代理服務器,我們的請求看起來像這樣https://api.openweathermap.org/data/2.5/weather?q=Thessaloniki,Greece&appid={API key},但是現在我們已經有了它,我們的請求看起來像這樣http://localhost/api?q=Thessaloniki,Greece。不需要添加必填字段appid,因為代理服務器自己將其添加為請求參數。當我們在 OpenWeatherMap API 上發出請求時,我們盡量不顯示 API 密鑰。
主要概念是將您的公共 API 密鑰隱藏在 API 代理服務器后面,以防止用戶竊取您的密鑰。為了實現這一點,它是創建端點來包裝實際開放 API 的端點,在需要此密鑰的每個請求中提供代理服務器內的 API 密鑰作為環境變量。這種方法的明顯缺點是這是一個耗時的過程,在某些情況下甚至不需要。
您可以在此處獲取此 API 代理服務器的源代碼。
我正在考慮向這個代理服務器添加一些功能。其中之一是添加緩存功能,以便更快地提供最近請求的數據。另一種是添加速率限制器,以防止用戶過度使用 API 并導致服務器崩潰。
如果您想到了另一種隱藏 API 密鑰的解決方案,或者您有任何提示或技巧要告訴我,請發表評論。
效果圖:
2 html骨架:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--網頁標題-->
<title>detection</title>
<!--內部css部分-->
<style>
......
</style>
</head>
<body>
<!--div部分-->
<div class="contain">
......
</div>
<!--內部js部分-->
<script>
......
</script>
</body>
</html>
3 css部分:
<!--內部css部分-->
<style>
/*網頁和body整體設置*/
html,body{
margin:0;
padding:0;
/*網頁背景顏色設置*/
background-color: rgb(96, 94, 212);
}
/*class='contain'在css的前面有點*/
.contain{
width:200px;
height: 200px;
font-size:25px;
text-align: center;
position: absolute;
left:50%;
top:50%;
transform:translate(-50%,-50%);
z-index:30;
}
/*警示label和結果label*/
.alertInfo,.resultInfo{
color:rgb(12, 231, 213);
font-weight: bold;
/*可以寫在這里,注意數字和px緊緊相鄰*/
width: 350px;
height: 10px;
}
/*輸入框的設置*/
.text{
width:150px;
/*文本框默認顯示,下面就是不顯示*/
/*outline:none;*/
text-align: center;
font-size:25px;
color:blue;
}
/*顯示框的設置*/
.show{
font-size:25px;
color:red;
}
</style>
4 body的div部分:
<!--div部分-->
<div class="contain">
<!--注意:style可以嵌套在里面,但不推薦,也可以單獨寫在上面的css內-->
<!--p class="alertInfo" style="width: 350px; height: 10px">顯示倒5個字符串的輸入框:</!--p-->
<p class="alertInfo" >顯示倒5個字符串的輸入框:</p>
<!--placeholder是指輸入框默認顯示文字-->
<input type="text" class="text" placeholder="請輸入內容">
<!--p class="resultInfo" style="width: 350px; height: 10px">顯示倒4個字符串的顯示區:</!--p-->
<p class="resultInfo" >顯示倒4個字符串的顯示區:</p>
<p class="show"></p>
</div>
5 body的js=JavaScript=script部分:
<!--內部js部分-->
<script>
// 被let聲明的變量不會作為全局對象window的屬性,而被var聲明的變量卻可以
//text和show均是class,所以前面有一個點
let input=document.querySelector(".text");
let show= document.querySelector(".show");
input.addEventListener('keyup',debounce(handle,100));
// 防抖處理
function debounce(func,wait){
let timeflag;
return function(){
clearTimeout(timeflag); //清除100ms之內之前觸發的定時器。
let arg=arguments;
let timethis = this;
timeflag = setTimeout(func.bind(timethis,arg),wait);
}
}
//回調函數
function handle(){
//輸入框內倒取5個字符串
input.value=input.value.slice(-5);
//輸入框內倒取4個字符串
show.textContent=input.value.slice(-4);
}
</script>
6 html部分基礎學習,自己整理并分享出來。
文將介紹驗證碼的歷史與發展、驗證碼破解的歷史與發展,驗證碼破解全流程實戰。
驗證碼,全稱為“Completely Automated Public Turing test to tell Computers and Humans Apart”,即全自動區分計算機和人類的圖靈測試,Captcha。早在上個世紀90年代,為了防止惡意的網絡機器人行為,像郵件轟炸、暴力破解密碼等,驗證碼應運而生。
最初的驗證碼是簡單的文本字符,如用戶只需輸入一組扭曲的字母和數字。然后驗證碼發展到圖像驗證碼,例如,要求用戶識別哪些圖片中包含某個特定對象(比如貓、狗或汽車等)。隨著技術的發展,更為復雜的驗證碼類型出現了,例如邏輯驗證碼(例如,3+4=?),音頻驗證碼(用戶必須聽音頻然后輸入聽到的字符)和3D驗證碼(用戶需要解讀3D對象或者場景)。
此外,也有一些新的驗證碼設計,為了提高用戶體驗同時維護網站安全,它們需要用戶進行更為人性化的操作。例如,滑動驗證碼讓用戶通過滑動解鎖,點擊驗證碼讓用戶點擊特定的圖片或文字,旋轉驗證碼則要求用戶調整圖片到正確的方向。
一些大公司也開發了自己的驗證碼系統。例如,Google的reCAPTCHA v2引入了復雜的圖像識別任務,需要用戶選擇包含特定物體(如汽車,交通燈)的圖片;而Google的reCAPTCHA v3則摒棄了用戶交互的方式,通過分析用戶的行為模式來確定是人類還是機器。同樣,第三方驗證服務如GeeTest CAPTCHA和hCaptcha等,也為網站提供了驗證服務,使得他們可以更好地防止自動化的惡意行為。
驗證碼破解的歷史,與驗證碼的發展緊密相連。早期的驗證碼破解主要依賴于OCR(Optical Character Recognition,光學字符識別)技術,這是一種將圖像中的文本轉換為機器可讀的字符的技術,用于識別簡單的文本驗證碼。
然而,隨著驗證碼的復雜性的增加,驗證碼破解也需要更為復雜的技術。例如,對于圖像驗證碼,可能需要使用圖像處理技術來處理噪聲和扭曲。這可能包括灰度化(將圖像轉換為黑白),二值化(將圖像進一步簡化為只有黑和白兩種顏色),邊緣檢測(識別圖像中的邊緣)等步驟。
對于更為復雜的驗證碼,例如點擊驗證碼和旋轉驗證碼,可能需要使用更復雜的機器視覺技術。這可能涉及到特征提取(識別圖像中的重要特征),對象識別(識別特定的對象或形狀),甚至深度學習(訓練模型來識別復雜的模式)。
近年來,隨著人工智能的發展,機器學習和深度學習等技術也被應用于驗證碼破解中。例如,卷積神經網絡(CNN)已經被用來識別復雜的圖像驗證碼,而遞歸神經網絡(RNN)可以用于識別音頻驗證碼。這些模型通過在大量的數據上進行訓練,可以學習到識別驗證碼的復雜模式,大大提高了驗證碼破解的準確性和效率。
人工驗證碼識別服務是一種基于人工智能或人工勞動力的驗證碼識別解決方案。當機器無法識別復雜的驗證碼時,這種服務能夠提供相對高效且準確的解決方案。
2Captcha是一種基于人工勞動力的驗證碼識別服務。它提供了一個API接口,允許開發者將無法識別的驗證碼發送到2Captcha服務。然后2Captcha的工人會手動識別并返回結果。這種服務對處理圖像驗證碼、文本驗證碼、點擊類驗證碼、GeeTest、reCAPTCHA、FunCaptcha等復雜驗證碼有很高的準確率,并且提供多種編程語言的接口文檔Python、PHP、Java、Go、Ruby、C++、C#。2Captcha的主要優點是其優異的精確性和靈活的API,使得開發者可以輕松集成并在不同環境中使用。
云碼基于圖像識別技術和人工輔助提供驗證碼識別服務,提供在線普通圖片、滑動、點選、谷歌、HCaptcha、數字計算題驗證碼識別服務。其對于圖像類的驗證碼有比較好的效果,尤其是各種不同類型的圖像驗證碼。但其對于復雜的驗證碼存在準確率下降和識別時間較長的情況、驗證碼種類跟進相較也會慢一些。
冰拓可識別各種常見圖片驗證碼,AI識別 + 真人識別雙模式,可高效識別坐標題、計算題、字符題、滑塊題、拼圖題等各種圖片。API支持Python、JAVA、PHP、JAVASCRIPT調用,支持按鍵精靈集成。對于多樣化的滑塊、拼圖、旋轉、坐標有自己獨特的處理方法和提供定制服務,不支持谷歌驗證碼。
超級鷹是專業的人工打碼平臺,對圖片數據進行精準、快速分類處理,并實時返還分類結果。支持英文數字、中文漢字、坐標選擇計算等多種類型圖片驗證碼,并且提供定制化的驗證碼識別服務。對于通用的驗證碼、傳統驗證碼有較好的識別效果,但對于復雜驗證碼尚未提供更多服務。
安裝2captcha-python
pip3 install 2captcha-python
破解驗證碼
# 導入BeautifulSoup、TwoCaptcha、requests庫
from bs4 import BeautifulSoup
from twocaptcha import TwoCaptcha
import requests
# TwoCaptcha服務的API秘鑰,你需要使用自己的
API_KEY = 'xxxxxxxxxxxxxx'
# 利用TwoCaptcha庫,使用提供的API秘鑰初始化一個solver對象,該對象可以解決ReCAPTCHA問題
solver = TwoCaptcha(API_KEY)
# 要抓取的網頁的URL
url = "https://www.scrapebay.com/spam"
# 這是ReCAPTCHA的site key,可以從網頁源碼中找到。
site_key='6LfGNEoeAAAAALUsU1OWRJnNsF1xUvoai0tV090n'
# 這個函數用來獲取CSRF token和cookies。它首先通過requests.get()獲取頁面內容,然后通過BeautifulSoup找到CSRF token。最后返回CSRF token和cookies。
def get_csrf_cookie(url):
response = requests.get(url)
soup = BeautifulSoup(response.text, "lxml")
csrf_el = soup.select_one('[name=csrfmiddlewaretoken]')
csrf = csrf_el['value']
cokkies = response.cookies
return csrf, cokkies
# 這個函數用來解決ReCAPTCHA問題。它使用TwoCaptcha solver對象的recaptcha()方法,如果發生異常則打印錯誤并退出。
def solve(url,sitekey):
try:
result = solver.recaptcha(sitekey=sitekey, url=url)
except Exception as e:
print(e)
exit()
return result
# 首先通過get_csrf_cookie(url)獲取CSRF token和cookies,然后通過solve(url,site_key)解決ReCAPTCHA問題,獲得ReCAPTCHA的驗證碼結果
def main():
csrf,cokkies = get_csrf_cookie(url)
print("csrf:",csrf)
print("cokkies:",cokkies)
result = solve(url,site_key)
print("captcha:",result)
if __name__ == "__main__":
main()
運行結果:
包含破解驗證碼的全部代碼如下:
# 導入BeautifulSoup、TwoCaptcha、requests庫
from bs4 import BeautifulSoup
from twocaptcha import TwoCaptcha
import requests
# 2Captcha服務的API秘鑰,你需要使用自己的
API_KEY = 'xxxxxxxxxxxxxx'
# 利用TwoCaptcha庫,使用提供的API秘鑰初始化一個solver對象,該對象可以解決ReCAPTCHA問題
solver = TwoCaptcha(API_KEY)
# 要抓取的網頁的URL
url = "https://www.scrapebay.com/spam"
# 這是ReCAPTCHA的site key,可以從網頁源碼中找到。
site_key='6LfGNEoeAAAAALUsU1OWRJnNsF1xUvoai0tV090n'
# 這個函數用來獲取CSRF token和cookies。它首先通過requests.get()獲取頁面內容,然后通過BeautifulSoup找到CSRF token。最后返回CSRF token和cookies。
def get_csrf_cookie(url):
response = requests.get(url)
soup = BeautifulSoup(response.text, "lxml")
csrf_el = soup.select_one('[name=csrfmiddlewaretoken]')
csrf = csrf_el['value']
cokkies = response.cookies
return csrf, cokkies
# 這個函數用來解決ReCAPTCHA問題。它使用TwoCaptcha solver對象的recaptcha()方法,如果發生異常則打印錯誤并退出。
def solve(url,sitekey):
try:
result = solver.recaptcha(sitekey=sitekey, url=url)
except Exception as e:
print(e)
exit()
return result
# 這個函數用來提交解決ReCAPTCHA后的頁面。它首先構建一個POST請求的payload,然后通過requests.post()方法發送請求。最后返回網頁的最后一列的文本。
def post_page(url, csrf, cookie, result):
payload = 'csrfmiddlewaretoken={}&g-recaptcha-response={}'
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': 'https://www.scrapebay.com/spam'
}
response = requests.post(url,data=payload.format(csrf,result),headers=headers,cookies=cookie)
soup = BeautifulSoup(response.text, "lxml")
el = soup.select_one('td:last-child')
return el.get_text()
# 先通過get_csrf_cookie(url)獲取CSRF token和cookies,然后通過solve(url,site_key)解決ReCAPTCHA問題,最后通過post_page(url,csrf,cokkies,result)提交頁面并打印出結果。
def main():
csrf,cokkies = get_csrf_cookie(url)
print("csrf:",csrf)
print("cokkies:",cokkies)
result = solve(url,site_key)
print("captcha:",result)
data = post_page(url,csrf,cokkies,result)
print("result:",data)
if __name__ == "__main__":
main()
網站驗證后的頁面:
運行結果:
至此我們使用2Captcha服務破解了reCAPTCHA v2,并獲得了需要爬取的內容。2Captcha服務包含多種驗證碼格式,均可以使用上述的流程,修改其中不同驗證碼的細節部分,攻克驗證碼的識別難點。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。