Nginx + uWSGI + Python + Django構建必應高清桌布站
寫在前面
做這個網站的初衷是因為,每次開啟必應搜尋搜東西的時候都會被上面的背景圖片吸引,我想必應的桌布應該是經過專業人員精選出來的,我甚至會翻看以前的歷史圖片,唯一美中不足的是必應的首頁只能檢視最多7天的桌布。所以我萌生出自己建一個網站,每天定時蒐集必應的桌布,將桌布資訊儲存在資料庫中,這樣就可以看到很久之前的桌布圖片了。網站使用的是python的django框架,前端接入使用了nginx+uwsgi。沒什麼特別的考慮,其實網站本身沒什麼技術含量,使用python的django入手還是很快的,當然用nodejs+express也是不錯的(其實我的node比python熟,想折騰點新東西哈哈)。我在這裡寫出步驟來,給剛剛上手的朋友們一個參考。伺服器是直接購買的阿里雲的,第一年很便宜才100不到好像,1核2G的基礎配置頻寬也低,不過夠用了。域名直接在萬網購買,其實也是阿里旗下,備案也很方便,按照提示步驟操作,差不多2周以內就下來了。最終的成果可以到這裡先睹為快:必應高清桌布,必應每日一圖
安裝python環境
我們使用的是最新的django框架,需要比較新版本的python環境,阿里雲的伺服器我購買的時候選擇的是centos 6.9,不過我覺得作業系統版本對後面的操作影響不大,伺服器內建都已經安裝有python環境,只不過是python2.6.6比較老的版本了。所以為了使用最新的django 3.0.1,我乾脆安裝最新的python 3.8.1。這裡我自己下載python原始碼進行編譯,安裝。
wget https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tgz tar zxvf Python-3.8.1.tgz cd Python-3.8.1 ./configure make make install
安裝好之後,python2.6與python3.8是共存的,我們可以使用python3命令來使用3.8.1版本的python,通過下面的命令可以看到我們安裝的python3.8被安裝到的目錄:
$ which python3 /usr/local/bin/python3 $ ll /usr/local/bin/python3 /usr/local/bin/python3 -> python3.8
跟隨python3一起安裝的還有pip3,是python的包管理工具,python2.x用的是pip,python3.x用的是pip3。接下來我們安裝django框架
安裝django框架
pip3 install django
結果報告下面的錯誤:
看提示是ssl的版本過低,而python需要更高的版本,使用命令 openssl version 檢視得到當前系統安裝的openssl的版本是1.0.1e,而python3.8需要openssl版本為1.0.2或者以上的版本。這裡我們安裝openssl 1.1.1的版本:
# 下載原始碼編譯安裝 wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz tar -zxvf openssl-1.1.1a.tar.gz cd openssl-1.1.1a ./config --prefix=/usr/local/openssl no-zlib make make install # 替換系統目錄中低版本的庫 mv /usr/bin/openssl /usr/bin/openssl.bak mv /usr/include/openssl/ /usr/include/openssl.bak ln -s /usr/local/openssl/include/openssl /usr/include/openssl ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/local/lib64/libssl.so ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so # 加入庫搜尋路徑並使之生效 echo "/usr/local/openssl/lib" >> /etc/ld.so.conf ldconfig -v # 檢視openssl版本輸出:OpenSSL 1.1.1a 20 Nov 2018 openssl version
這樣新版openssl就安裝好了,我們再重新編譯並安裝Python3,如下:
cd Python-3.8.1 ./configure --with-openssl=/usr/local/openssl make make install
這裡的3.8.1編譯的時候是新增 --with-openssl=/usr/local/openssl 這個選項,而不是網上的資料說的 --with-ssl 網上說的這個選項是錯的,會報錯 unrecognized options 。除此以外還有一個問題讓我費了點時間值得注意一下,就是在openssl進行make install之後,重新編譯python3.8的時候,編譯結束總是有下面的錯誤提示:
Could not build the ssl module! Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
就是提示找不到ssl,該錯誤提示還是因為編譯python的時候 -ssl 選項沒有找到正確的 libssl.so 的動態庫。我們可以通過下面的命令來確定當前系統中的ssl動態庫的情況:
ldconfig -v | grep ssl # 在其輸出中我們要確定是否還有老的ssl庫在裡面,實際上在編譯提示找不到ssl的時候 # 我通過命令檢視的結果發現 /usr/lib64/libssl.so 軟鏈的還是 1.0.1 的老版本 # 於是我改成連線到新編譯的 1.1.1 版本之後,最後看到的是下面的結果 libssl.so.1.1 -> libssl.so.1.1 libssl3.so -> libssl3.so libssl.so.10 -> libssl.so.1.0.1e
之後再重新編譯python就沒有報ssl not found的錯誤了,說明新版ssl已經編譯到python3.8.1中,此時我們再用上面的命令安裝django,最後得到下面的提示,表示安裝成功完成:
Installing collected packages: sqlparse, pytz, asgiref, Django Successfully installed Django-3.0.5 asgiref-3.2.7 pytz-2019.3 sqlparse-0.3.1
這裡要注意的是,網路很慢的情況下會經常超時,我之後是通過wget手工下載之後再進行安裝的:
wget https://files.pythonhosted.org/packages/a9/4f/8a247eee2958529a6a805d38fbacd9764fd566462fa0016aa2a2947ab2a6/Django-3.0.5-py3-none-any.whl pip3 install ./Django-3.0.5-py3-none-any.whl
安裝成功之後,我們通過下面的方法驗證是否正常:
python3 Python 3.8.1 (default, Apr 18 2020, 00:10:11) [GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import django >>> print(django.get_version()) 3.0.5
就是直接執行python3,開啟python3的互動輸入,引用django模組,打印出其版本,正確打印出了我們安裝的3.0.5版本,說明安裝正常了
配置django
django框架安裝正常之後,我們建立一個簡單的django工程testdj如下:
django-admin.py startproject testdj
建立完成之後,會在當前目錄下建立一個目錄與工程名同名 testdj,我們看下該目錄的結構:
這樣我們的django專案就建立好了,我們通過其提供的管理指令碼 manage.py 來啟動他:
# 注意這裡要用python3來執行 python3 manage.py runserver 0.0.0.0:8000
執行之後報錯了:
由於django3.0.5版本預設引用了sqlite3的資料庫,我們並沒有安裝sqlite3,所以報錯,我們先在 settings.py 中把這個配置去掉:
再次執行之後正常,但是此時我們還不能在瀏覽器中訪問他,我們需要編寫對應的頁面,因為此時專案中什麼都沒有,連主頁都沒有,執行成功如下圖:
編寫檢視以及設定url路由
下面我們為主頁的請求編寫一個view並配置一下路由規則,讓主頁請求路由到我們編寫的view上,在上面的目錄結構裡面,與 settings.py 同一目錄下新增檔案 view.py 內容如下:
# view.py from django.http import HttpResponse def hello(request): return HttpResponse("Hello world ! ")
修改urls.py的內容如下:
# urls.py from django.contrib import admin from django.urls import path from django.conf.urls import url from . import view urlpatterns = [ url(r'^$', view.hello), ]
將 settings.py 中的 ALLOWED_HOSTS 配置修改為如下:
# 如果不修改會報類似的錯誤 # Invalid HTTP_HOST header: 'ip:8000'. You may need to add 'ip' to ALLOWED_HOSTS. ALLOWED_HOSTS = ['*']
再次啟動專案之後,在瀏覽器通過地址訪問得到正確輸出:
此時我們的diango順利啟動,下面我們在django中使用資料庫,django中預設配置sqlite3,我們這裡為演示方便,也使用sqlite3作為例子,相信換成其他的資料庫不難
在django中使用sqlite3
我們使用sqlite3這個小巧簡單的單檔案資料庫來做演示,sqlite3雖然結構簡單,但是功能可一點不簡單,支援大多數常見的sql語法,首先我們需要安裝sqlite3:
wget https://www.sqlite.org/2018/sqlite-autoconf-3240000.tar.gz tar -xvzf sqlite-autoconf-3240000.tar.gz cd sqlite-autoconf-3240000/ ./configure --prefix=/usr/local/sqlite make make install
編譯完成之後,我們需要重新編譯與安裝python3.8.1,按照上面編譯python3的流程重新跑一遍(包括 ./configure --with-openssl=/usr/local/openssl
) ,重新編譯python3之後,我們可以開啟python3的輸入互動環境,直接在裡面 import sqlite3 沒有報錯,即sqlite3可以在python3中正常使用了,如果有報錯的話,按照我們上面解決 openssl 的思路去定位類似的問題,相信應該很好解決。在呼叫configure配置python3的時候,會生成 config.log 裡面也可以檢視到一些出錯資訊。接下來我們首先生成一個sqlite3的資料庫檔案,並建立一個表,插入測試資料,過程如下:
# 我們的資料庫檔案的名字取 db.sqlite3 sqlite3 db.sqlite3 create table "tb_message" ( "message_id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "message_user" varchar(255) NOT NULL, "message_content" text default '' ); insert into tb_message(message_user,message_content)values('張三','這是張三傳送的訊息'); insert into tb_message(message_user,message_content)values('李四','這是李四傳送的訊息');
將生成的資料庫檔案的名字放在想要放置的目錄下,為了測試方便,我們將其放在django工程的根目錄,我們將在django專案中讀出表的資料並展示到網頁上,為了使用django的model,我們需要先建立一個app,在django工程的根目錄下使用下面的命令建立一個名字為djapp的app:
django-admin startapp djapp
我們看到建立了一個djapp的資料夾,我們看看djapp的目錄結構:
我們前面為了順利執行django專案,將settings.py中關於sqlite的配置註釋了,現在我們需要將這些配置正常化,同時我們剛才建立的djapp我們要在 settings.py 配置中新增進來:
# settings.py # 這裡配置了資料庫檔案所在的路徑 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } ... # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'djapp', ]
生成model定義,也就是 djapp/models.py 的內容,在django中,我們可以自己編寫models.py的內容,然後使用相關的命令生成資料庫的表結構,反過來我們可以自己定義好表結構,使用相關命令由表結構去生成model的類定義。我一般習慣於自己定義好資料庫的表結構,然後使用命令生成model的類定義,下面我們生成model類定義到檔案 djapp/models.py 中:
# 我們在manage.py所在的目錄執行下面的命令 python3 manage.py inspectdb > djapp/models.py
我們可以在 djapp/models.py 檔案中看到生成的model定義的內容,一個數據庫表對應一個class,我們只建立了一個表,所以檔案中只有一個模型類,要注意的是這一步驟的前提是必須在 settings.py 中設定sqlite3的相關配置:
from django.db import models class TbMessage(models.Model): message_id = models.AutoField(primary_key=True) message_user = models.CharField(max_length=255) message_content = models.TextField(blank=True, null=True) class Meta: managed = False db_table = 'tb_message'
接著我們修改之前 view.hello 的實現,在裡面讀取資料庫表的記錄,並將資料呈現到模板檔案中,再編寫模板檔案之前,我們需要在 settings.py 中設定模板檔案所在的目錄:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR+"/templates"], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
我們將模板檔案放在專案根目錄下的 templates 目錄下,我們在此目錄下新建一個模板檔案 test.tmp 內容如下:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>django test</title> </head> <body> {% for msg in msg_list %} <div>使用者名稱:{{ msg.message_user }} 訊息:{{ msg.message_content }} </div> {% endfor %} </body> </html>
django的模板提供各種包括if、for、過濾器等豐富的模板標籤來控制模板的呈現邏輯,使用過MVC方式編寫Web應用程式的應該很容易理解,具體的用法很容易在網路上找到,我也不再說明了,上面的模板實際上就是將後端返回的資料中對應的model資料呈現到模板檔案中,然後返回最終呈現的HTML內容,我們的 testdj/view.py 的內容如下:
# view .py from django.http import HttpResponse from django.shortcuts import render from django.http import JsonResponse from djapp.models import TbMessage def hello(request): xlist = TbMessage.objects.all().order_by('message_id') msg_list = [] context={"msg_list":msg_list} for msg in xlist: msg_list.append({"message_user":msg.message_user,"message_content":msg.message_content}) return render(request, 'test.tmp', context)
django生成的模板類提供了豐富的訪問資料庫的能力,包括按各種條件去查詢資料庫以及進行排序等,另外通過 Model.objects.raw() 函式可以直接寫自定義的sql,資料訪問這部分更多的函式功能可以查詢django的文件,這裡也不在浪費篇幅說明了,上述操作好之後,我們再啟動django的專案,輸入網址,在網頁上就能看到結果了:
至此我們的django專案已經執行起來了,並且可以訪問sqlite3資料庫中的資料,我們列出目前為止整個專案目錄的結構以及其說明,方便大家參考:
到目前為止我們執行django專案都是通過專案目錄下的 manage.py 進行執行,此種方式僅僅是django為方便除錯而提供的一個簡易的web伺服器,在線上環境我們肯定不能這麼使用,那麼接下來我們需要通過 Nginx、uWSGI與django結合的方式搭建可以在線上部署的方案
安裝uWSGI
在開始這個話題之前,我們首先來說明幾個比較重要的概念:
首先要說明的是WSGI,他的全稱叫做Web伺服器閘道器介面(Python Web Server Gateway Interface,縮寫為WSGI)是為Python語言定義的Web伺服器和Web應用程式或框架之間的一種簡單而通用的介面。WSGI 不是框架,也不是一個模組而是一個介面規範,是Web伺服器與Web應用之間的一種通訊規範,該規範不僅僅侷限於Python語言,任何語言編寫的Web伺服器和Web應用程式之間都可以使用WSGI來通訊。WSGI標準在 PEP 333 中定義並被許多框架實現,其中包括現我們這裡的django框架
說了這麼多到底WSGI是什麼呢,WSGI只是一種規範,是用於Web伺服器和Web應用程式之間通訊用的,Web伺服器我們知道是提供HTTP服務的服務端程式,例如Nginx、Apache Http Server、Windows IIS 都是常見的Web伺服器程式,那麼Web應用程式又是什麼呢。講這個之前我們需要先回顧一下Web程式的發展歷史,HTTP協議出來之後,作為服務端的實現,Web伺服器開始只能提供對靜態資源的訪問,例如html、圖片資源等等,像下面的形式:
人們不滿足於只獲取靜態的網頁內容,就出現了動態的網頁技術,由Web伺服器呼叫一個外部的程式來生成動態的HTML內容返回給瀏覽器端。而這個外部的程式可以使用shell,也可以使用perl等指令碼編寫,或者乾脆使用C語言編寫,這些程式可以訪問外部資料來源來生成HTML。那麼Web伺服器程式與這個生成動態HTML內容的外部程式之間通過什麼來傳遞請求引數呢,Web伺服器又通過什麼方式來獲得並返回由外部程式生成的動態HTML內容呢。由此定義了一個規範,也即是Common Gateway Interface,公共閘道器介面規範,就是我們常說的CGI了,這些被Web伺服器呼叫的外部程式也因此被稱為CGI程式。CGI規範規定:CGI程式從他的標準輸入中,接受Web伺服器的輸入(例如請求引數),並通過標準輸出將生成的HTML內容返回給Web伺服器。HTTP請求中的一些變數(例如Host,客戶端ip地址,瀏覽器的Agent資訊等)則是由Web伺服器設定在環境變數中,再由CGI程式從環境變數中讀取,這種請求模式變成下面的圖:
之後出現了CGI規範的改進版,也即FastCGI規範,FastCGI程式與Web伺服器之間的通訊並不是通過標準輸入與輸出,也不通過環境變數來與Web伺服器交換HTTP的變數資訊,FastCGI程式本身是一個獨立的服務端程式,其通過socket監聽埠,與Web伺服器通訊,只不過通訊協議使用FastCGI協議而已。那麼我們這裡說的CGI程式與FastCGI程式是用來處理動態的Web請求並動態生成HTML內容返回給Web伺服器的,他們就是我們所說的Web應用程式。隨著動態語言的發展,湧現出了越來越多的動態網頁技術,但是總歸其模式與上面講的差異不大,例如我們常見的語言的請求結構如下圖所示:
之所以需要Web伺服器與Web應用程式這種架構,是因為Web伺服器本身不處理動態內容,動態內容的處理交給Web應用程式去處理,Web應用程式由廣大的程式設計師根據自己的業務需求使用各種各樣的語言去編寫,而Web伺服器與Web應用程式之間通過某種規範或者說協議來規定怎樣去通訊,這就出現了各種語言框架下實現的CGI、FastCGI、Servlet、Rack、WSGI等協議或規範,Web伺服器與Web應用程式之間如果都遵循相同的協議或實現相同的規範,理論上應該是與語言無關的,由於各種各樣的原因,有些規範或者協議,只在特定的語言的web框架中出現或者說多數情況下是這樣,例如Servlet在Java中使用,Rack在Ruby中使用
在一些情況下Web伺服器與Web應用程式是兩個獨立的程序,他們通過socket進行通訊,通訊協議是雙方都支援的協議規範(例如FastCGI)。還有一些情況Web伺服器與Web應用程式之間的通訊是緊耦合的,比如IIS是通過ISAPI的方式,實際上是載入一個dll,呼叫dll中的相關功能與.NET Web應用互動的。當Nginx與Python Django結合的時候他支援這兩種方式,一種是 Nginx+mod_wsgi 方式,這種方式下由Nginx去呼叫 mod_wsgi 模組中的功能,進而呼叫python的Web應用程式功能動態生成HTML,其執行的上下文環境在 Nginx 程序中:
另一種方式就是上面截圖中展示的通過socket與uWSGI程序互動的方式,Web伺服器與uWSGI通訊的協議可以是 HTTP 協議,也可以是二進位制的 uwsgi 協議,uWSGI程式支援這兩種方式與之通訊,我們這裡使用二進位制 uwsgi 協議的方式,不過我們首先要安裝 uWSGI 程式(終於說到本章的正題了,前面講原理都是做鋪墊):
pip3 install uwsgi ModuleNotFoundError: No module named '_ctypes'
報錯找不到模組 '_ctypes' 經查詢我們需要安裝 libffi-devel 命令如下:
yum install libffi-devel -y
安裝完成之後,我們需要重新配置Python3.8.1並重新make以及make install,命令在上面都有,這裡就不重複說了,完成之後繼續安裝 uwsgi 沒有報錯,安裝成功,我們嘗試用下面的命令通過uwsgi啟動django應用:
uwsgi --http :8000 --wsgi-file testdj/wsgi.py
我們之前說過uWSGI程式支援兩種方式接受請求,一種是使用 HTTP 協議,另一種是使用二進位制的 uwsgi 協議,這裡我們需要在瀏覽器中直接訪問,所以我們這裡執行 uwsgi 的時候通過 --http 選項指定 http 協議,並指定 wsgi 應用檔案所在的路徑為django專案根目錄下的 testdj/wsgi.py 檔案,啟動之後在瀏覽器中輸入地址直接訪問即可正確出結果,截圖與前面一樣。接下來我們需要使用 Nginx 來作為Web伺服器並通過uwsgi程序與wsgi應用來處理動態請求。為什麼我們需要Nginx呢,上面執行uwsgi不是已經可以直接使用了嗎,我們在之前已經說過了,現在的網站的結構一般都是 Web伺服器程式 + 動態語言程式 的結構,是因為各個模組應該各自做自己擅長的事,wsgi應用擅長處理動態的http請求並生成動態的HTML內容,Nginx是專業的Web伺服器擅長其他的HTTP請求的處理,事實上uWSGI程式中實現了一個簡陋的HTTP服務,所以我們才可以通過 HTTP 的方式直接在瀏覽器中訪問他,然而如果靜態資源也用他來處理,其效能肯定比Nginx差很多,所以這裡要引入Nginx,引入Nginx的另一個好處是還可以做負載均衡
安裝Nginx
首先我們需要安裝Nginx服務,Nginx是使用非常廣泛的高效能Web伺服器,在CentOS下安裝也非常簡單:
yum install nginx
沒有任何報錯,直接安裝完成,當然自己下載原始碼安裝想要的版本也很方便,下面我們需要配置Nginx,安裝之後的nginx的配置檔案地址在 /etc/nginx/conf.d/default.conf
server { ... listen 80; # 靜態檔案請求 location /static { alias /data/testdj/static/; } # uwsgi_pass 轉向到uWSGI的8000埠 location / { uwsgi_pass 127.0.0.1:8000; include /etc/nginx/uwsgi_params; } ... }
這裡我列出了比較關鍵的配置,第一個static匹配用於請求靜態資源,我們的靜態資源可以放在一個單獨的 static 目錄中,這樣靜態資源請求不會轉發到 uWSGI 去處理,而是直接由 Nginx 處理返回,其他的請求我們通過 uwsgi_pass 配置轉發到本機的 8000 埠上,實際上這個配置表明我們的 uWSGI 程序開啟的是以 uwsgi 二進位制協議進行 socket 通訊的8000埠,而不是上面的 HTTP 協議的 8000 埠,如果是 HTTP 協議的8000埠,這裡直接配置一個普通的 http 代理即可,配置完成之後 ,我們以下面的命令啟動 uWSGI程式:
uwsgi --socket 127.0.0.1:8000 --wsgi-file testdj/wsgi.py
我們這裡使用的是 --socket 而不是 --http 並且監聽的是 127.0.0.1 這個地址,因為我們的Nginx與uWSGI程序執行在同一臺機器上,這個埠就不用暴露到外面了,啟動 uWSGI 之後,我們啟動 Nginx程序,直接在瀏覽器中輸入 http://ip 即可以正常訪問了
在後端執行uWSGI程序
我們前面通過 uwsgi 命令啟動uWSGI的方式,程式跑在我們shell環境的前端,如果我們的終端連線斷掉則程式會退出,我們需要以後端服務的形式執行uWSGI,這裡我們需要將 uWSGI 執行所需要的引數放到一個配置檔案中,我們將這些引數放在 uwsgi.ini 中,當然這個檔名字以及放置的具體路徑並沒有特殊要求,檔案內容如下:
# uwsgi.ini [uwsgi] # uWSGI的埠 socket = 127.0.0.1:8000 # 直接作為web伺服器使用 # http=ip:port # django專案目錄 chdir = /data/testdj # 以django專案名命名的wsgi檔案,實際上這個檔案是不存在的 # 但是配置必須這麼配 module = testdj.wsgi master = true #程序數 processes = 4 threads = 2 vacuum = true # 儲存啟動之後主程序的pid pidfile=uwsgi.pid # 設定uwsgi後臺執行,uwsgi.log儲存日誌資訊 daemonize=uwsgi.log
設定好之後,我們在 uwsgi.ini 檔案所在的目錄執行下面的命令即可(Nginx不用重啟):
# -d 引數表示從後臺執行 uwsgi -d --ini uwsgi.ini
再次訪問網頁,大功告成
收集必應桌布
文章開頭我們說我們要建立一個必應桌布的收集展示網站,其實主要是介紹 Nginx+uWSGI+Django 的使用,因為網站使用的是 Python語言和Django框架,所以搭建網站也費了一些周折,這個是耗時最多的,其實環境搭建好之後,程式碼的編寫反而很簡單,在django中編寫程式很方便。收集必應桌布本身並沒有什麼特別要說明的,就是下載每天的必應美圖,將圖片儲存到自己的網站,並將相關資訊入庫,在網站上展示出來。不過呢這裡簡單說一下怎麼獲取必應的背景桌布,有一種很容易想到的方法是直接在程式碼裡面請求必應的網站,然後檢視網頁結構,獲取必應桌布的url,不過必應的桌布並沒有這麼麻煩,通過在Chrome瀏覽器中訪問必應網站發現,必應其實有提供介面,如下:
通過在Chrome瀏覽器中請求必應網站,選擇 "XHR" 可以看到必應的桌布是通過一個 Ajax 請求獲取的資料,我們找到這個請求即可,我貼出來:
https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1587287726147&pid=hp
這個接口裡面的引數是可以設定的,format表示返回的資料的格式 js 返回的是json格式的資料,n 應該是返回的圖片的張數,idx 應該是分頁的引數,具體的引數含義,大家可以去網上搜索一下,已經有一些人研究過了。不過好像無論怎麼設定,並沒有辦法獲取太久的歷史圖片資料,必應的官網上也只能看到最近一週的圖片。也因如此,才有了本篇文章,必應桌布收集站的實現完全使用上面提到的技術,網站也會持續完善中,歡迎大家來這裡反饋留言:關於必應高清桌布。另外伺服器我直接從阿里雲買的低配版本機器,頻寬和效能都比較基礎,目前來說是夠用的,域名是直接從萬網購買並備案的,其實整個流程還是很便捷的,而且第一年的價格很便宜。 到此本篇介紹就完結了,希望對大家使用django搭建web網站有所