整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          四種常見的 POST 提交數據方式

          四種常見的 POST 提交數據方式

          介:

          HTTP/1.1 協議規定的 HTTP 請求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 這幾種。其中 POST 一般用來向服務端提交數據,本文主要討論 POST 提交數據的幾種方式。

          我們知道,HTTP 協議是以 ASCII 碼傳輸,建立在 TCP/IP 協議之上的應用層規范。規范把 HTTP 請求分為三個部分:狀態行、請求頭、消息主體。類似于下面這樣:

          <method> <request-URL> <version><headers><entity-body>

          協議規定 POST 提交的數據必須放在消息主體(entity-body)中,但協議并沒有規定數據必須使用什么編碼方式。實際上,開發者完全可以自己決定消息主體的格式,只要最后發送的 HTTP 請求滿足上面的格式就可以。

          但是,數據發送出去,還要服務端解析成功才有意義。一般服務端語言如 php、python 等,以及它們的 framework,都內置了自動解析常見數據格式的功能。服務端通常是根據請求頭(headers)中的 Content-Type 字段來獲知請求中的消息主體是用何種方式編碼,再對主體進行解析。所以說到 POST 提交數據方案,包含了 Content-Type 和消息主體編碼方式兩部分。下面就正式開始介紹它們。

          application/x-www-form-urlencoded

          這應該是最常見的 POST 提交數據的方式了。瀏覽器的原生 <form> 表單,如果不設置 enctype 屬性,那么最終就會以 application/x-www-form-urlencoded 方式提交數據。請求類似于下面這樣(無關的請求頭在本文中都省略掉了):

          POST http://www.example.com HTTP/1.1

          Content-Type: application/x-www-form-urlencoded;charset=utf-8

          title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

          首先,Content-Type 被指定為 application/x-www-form-urlencoded;其次,提交的數據按照 key1=val1&key2=val2 的方式進行編碼,key 和 val 都進行了 URL 轉碼。大部分服務端語言都對這種方式有很好的支持。例如 PHP 中,$_POST['title'] 可以獲取到 title 的值,$_POST['sub'] 可以得到 sub 數組。

          很多時候,我們用 Ajax 提交數據時,也是使用這種方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默認值都是「application/x-www-form-urlencoded;charset=utf-8」。

          multipart/form-data

          這又是一個常見的 POST 數據提交的方式。我們使用表單上傳文件時,必須讓 <form> 表單的 enctype 等于 multipart/form-data。直接來看一個請求示例:

          POST http://www.example.com HTTP/1.1Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name="text"title------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name="file"; filename="chrome.png"Content-Type: image/pngPNG ... content of chrome.png ...------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

          這個例子稍微復雜點。首先生成了一個 boundary 用于分割不同的字段,為了避免與正文內容重復,boundary 很長很復雜。然后 Content-Type 里指明了數據是以 multipart/form-data 來編碼,本次請求的 boundary 是什么內容。消息主體里按照字段個數又分為多個結構類似的部分,每部分都是以 --boundary 開始,緊接著是內容描述信息,然后是回車,最后是字段具體內容(文本或二進制)。如果傳輸的是文件,還要包含文件名和文件類型信息。消息主體最后以 --boundary-- 標示結束。關于 multipart/form-data 的詳細定義,請前往 rfc1867 查看。

          這種方式一般用來上傳文件,各大服務端語言對它也有著良好的支持。

          上面提到的這兩種 POST 數據的方式,都是瀏覽器原生支持的,而且現階段標準中原生 <form> 表單也只支持這兩種方式(通過 <form> 元素的 enctype 屬性指定,默認為 application/x-www-form-urlencoded。其實 enctype 還支持 text/plain,不過用得非常少)。

          隨著越來越多的 Web 站點,尤其是 WebApp,全部使用 Ajax 進行數據交互之后,我們完全可以定義新的數據提交方式,給開發帶來更多便利。

          application/json

          application/json 這個 Content-Type 作為響應頭大家肯定不陌生。實際上,現在越來越多的人把它作為請求頭,用來告訴服務端消息主體是序列化后的 JSON 字符串。由于 JSON 規范的流行,除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify,服務端語言也都有處理 JSON 的函數,使用 JSON 不會遇上什么麻煩。

          JSON 格式支持比鍵值對復雜得多的結構化數據,這一點也很有用。記得我幾年前做一個項目時,需要提交的數據層次非常深,我就是把數據 JSON 序列化之后來提交的。不過當時我是把 JSON 字符串作為 val,仍然放在鍵值對里,以 x-www-form-urlencoded 方式提交。

          Google 的 AngularJS 中的 Ajax 功能,默認就是提交 JSON 字符串。例如下面這段代碼:

          var data={'title':'test', 'sub' : [1,2,3]};$http.post(url, data).success(function(result) { ...});

          最終發送的請求是:

          POST http://www.example.com HTTP/1.1 Content-Type: application/json;charset=utf-8{"title":"test","sub":[1,2,3]}

          這種方案,可以方便的提交復雜的結構化數據,特別適合 RESTful 的接口。各大抓包工具如 Chrome 自帶的開發者工具、Firebug、Fiddler,都會以樹形結構展示 JSON 數據,非常友好。但也有些服務端語言還沒有支持這種方式,例如 php 就無法通過 $_POST 對象從上面的請求中獲得內容。這時候,需要自己動手處理下:在請求頭中 Content-Type 為 application/json 時,從 php://input 里獲得原始輸入流,再 json_decode 成對象。一些 php 框架已經開始這么做了。

          text/xml

          我的博客之前提到過 XML-RPC(XML Remote Procedure Call)。它是一種使用 HTTP 作為傳輸協議,XML 作為編碼方式的遠程調用規范。典型的 XML-RPC 請求是這樣的:

          HTML

          POST http://www.example.com HTTP/1.1 Content-Type: text/xml<?xml version="1.0"?><methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params></methodCall>

          XML-RPC 協議簡單、功能夠用,各種語言的實現都有。它的使用也很廣泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服務等等。JavaScript 中,也有現成的庫支持以這種方式進行數據交互,能很好的支持已有的 XML-RPC 服務。不過,我個人覺得 XML 結構還是過于臃腫,一般場景用 JSON 會更靈活方便。

          、軟件準備

          1.安裝Python 環境

          首先需要你的電腦安裝好了Python環境,并且安裝好了Python開發工具。

          如果你還沒有安裝,可以參考以下文章:

          如果僅用Python來處理數據、爬蟲、數據分析或者自動化腳本、機器學習等,建議使用Python基礎環境+jupyter即可,安裝使用參考Windows/Mac 安裝、使用Python環境+jupyter notebook

          2.安裝selenium庫

          pip install selenium
          復制代碼

          3.下載谷歌瀏覽器驅動chromedriver,下載地址:npm.taobao.org/mirrors/chr…

          需要選擇對應的谷歌瀏覽器版本,(谷歌瀏覽器訪問:chrome://settings/help,即可查看版本)

          下載好后,隨便發到一個路徑下即可(簡單點最好,記住路徑)。

          二、實現方法

          2.1 使用 Selenium 工具自動化模擬瀏覽器,當前重點是了解對元素的定位

          我們想定位一個元素,可以通過 id、name、class、tag、鏈接上的全部文本、鏈接上的部分文本、XPath 或者 CSS 進行定位,在 Selenium Webdriver 中也提供了這 8 種方法方便我們定位元素。

          1)通過 id 定位:我們可以使用 find_element_by_id() 函數。比如我們想定位 id=loginName 的元素,就可以使用browser.find_element_by_id(“loginName”)。

          2)通過 name 定位:我們可以使用 find_element_by_name() 函數,比如我們想要對 name=key_word 的元素進行定位,就可以使用 browser.find_element_by_name(“key_word”)。

          3)通過 class 定位:可以使用 find_element_by_class_name() 函數。

          4)通過 tag 定位:使用 find_element_by_tag_name() 函數。

          5)通過 link 上的完整文本定位:使用 find_element_by_link_text() 函數。

          6)通過 link 上的部分文本定位:使用 find_element_by_partial_link_text() 函數。有時候超鏈接上的文本很長,我們通過查找部分文本內容就可以定位。

          7)通過 XPath 定位:使用 find_element_by_xpath() 函數。使用 XPath 定位的通用性比較好,因為當 id、name、class 為多個,或者元素沒有這些屬性值的時候,XPath 定位可以幫我們完成任務。

          8)通過 CSS 定位:使用 find_element_by_css_selector() 函數。CSS 定位也是常用的定位方法,相比于 XPath 來說更簡潔。

          2.2 對元素進行的操作包括

          1)清空輸入框的內容:使用 clear() 函數;

          2)在輸入框中輸入內容:使用 send_keys(content) 函數傳入要輸入的文本;

          3)點擊按鈕:使用 click() 函數,如果元素是個按鈕或者鏈接的時候,可以點擊操作;

          4)提交表單:使用 submit() 函數,元素對象為一個表單的時候,可以提交表單;

          2.3 注意

          由于selenium打開的chrome是原始設置的,所以訪問微博首頁時一定會彈出來是否提示消息的彈窗,導致不能定位到輸入框。可使用如下方法關閉彈窗:

          prefs={"profile.default_content_setting_values.notifications": 2}
          復制代碼

          2.4 如何定位元素

          點擊需要定位的元素,然后右鍵選擇檢查,可以調出谷歌開發者工具。

          獲取xpath 路徑,點擊谷歌開發者工具左上角的小鍵頭(選擇元素),選擇自己要查看的地方的,開發者工具就會自動定位到對應元素的源碼位置,選中對應源碼,然后右鍵,選擇Copy-> Copy XPath即可獲取到xpath 路徑。

          另外: 可以下載 XPath Helper插件,安裝后 在網頁上選取想要提取的元素, 點擊右鍵 選中 檢查 然后 開發者工具自動打開 你可以看到 HTML代碼 ,選中然后再次點擊右鍵,選中copy 里的 copy to xpath這樣就得到了xpath的值了。

          三、完整代碼

          實現思路: 其實和平時我們正常操作一樣,只不過這里,全程由selenium來實現,模擬點擊和輸入,所以整個過程為:打開登錄頁面->輸入賬號密碼->點擊登錄按鈕->在發微博框輸入發送內容->點擊發送按鈕->關閉瀏覽器(自選)。

          3.1 目前自動輸入賬號可能會彈出登錄保護需掃二維碼驗證

          from selenium import webdriver
          from selenium.webdriver.chrome.service import Service
          import time
          
          
          '''
          自動發布微博
          content:發送內容
          username:微博賬號
          password:微博密碼
          '''
          def post_weibo(content, username, password):
              # 加載谷歌瀏覽器驅動
              path=r'C:/MyEnv/chromedriver.exe '  # 指定驅動存放目錄
              ser=Service(path)
              chrome_options=webdriver.ChromeOptions()
              # 把允許提示這個彈窗關閉
              prefs={"profile.default_content_setting_values.notifications": 2}
              chrome_options.add_experimental_option("prefs", prefs)
              driver=webdriver.Chrome(service=ser, options=chrome_options)
              driver.maximize_window()  # 設置頁面最大化,避免元素被隱藏  
              
              print('# get打開微博主頁')
              url='http://weibo.com/login.php'
              driver.get(url)  # get打開微博主頁
              time.sleep(5)  # 頁面加載完全
              
              print('找到用戶名 密碼輸入框')
              input_account=driver.find_element_by_id('loginname')  # 找到用戶名輸入框
              input_psw=driver.find_element_by_css_selector('input[type="password"]')  # 找到密碼輸入框
              # 輸入用戶名和密碼
              input_account.send_keys(username)
              input_psw.send_keys(password)
              
              print('# 找到登錄按鈕 //div[@node-type="normal_form"]//div[@class="info_list login_btn"]/a')
              bt_logoin=driver.find_element_by_xpath('//div[@node-type="normal_form"]//div[@class="info_list login_btn"]/a')  # 找到登錄按鈕
              bt_logoin.click()  # 點擊登錄
              # 等待頁面加載完畢  #有的可能需要登錄保護,需掃碼確認下
              time.sleep(40)
          
              # 登錄后 默認到首頁,有微博發送框
              print('# 找到文本輸入框 輸入內容 //*[@id="homeWrap"]/div[1]/div/div[1]/div/textarea')
              weibo_content=driver.find_element_by_xpath('//*[@id="homeWrap"]/div[1]/div/div[1]/div/textarea')
              weibo_content.send_keys(content)
              print('# 點擊發送按鈕 //*[@id="homeWrap"]/div[1]/div/div[4]/div/button')
              bt_push=driver.find_element_by_xpath('//*[@id="homeWrap"]/div[1]/div/div[4]/div/button')
              bt_push.click()  # 點擊發布
              time.sleep(15)
              
              driver.close()  # 關閉瀏覽器
          
          if __name__=='__main__':
              username='微博用戶名'
              password="微博密碼"
              # 自動發微博
              content='每天進步一點'
              post_weibo(content, username, password)
          復制代碼

          通過cookie進行登錄可跳過掃碼登錄,cookie過期后重新獲取下cookie就可以了。

          導入第三方包

          from selenium import webdriver
          from selenium.webdriver.chrome.service import Service
          import time
          import requests
          import json
          復制代碼

          獲取cookie到本地

          這里主要利用了selenium的get_cookies函數獲取cookies。

          # 獲取cookies 到本地
          def get_cookies(driver):
              driver.get('https://weibo.com/login.php')
              time.sleep(20) # 留時間進行掃碼
              Cookies=driver.get_cookies() # 獲取list的cookies
              jsCookies=json.dumps(Cookies) # 轉換成字符串保存
              with open('cookies.txt', 'w') as f:
                  f.write(jsCookies)
              print('cookies已重新寫入!')
              
          
          # 讀取本地的cookies
          def read_cookies():
              with open('cookies.txt', 'r', encoding='utf8') as f:
                  Cookies=json.loads(f.read())
              cookies=[]
              for cookie in Cookies:
                  cookie_dict={
                      'domain': '.weibo.com',
                      'name': cookie.get('name'),
                      'value': cookie.get('value'),
                      'expires': '',
                      'path': '/',
                      'httpOnly': False,
                      'HostOnly': False,
                      'Secure': False
                  }
                  cookies.append(cookie_dict)
              return cookies
          復制代碼

          利用cookie登錄微博并發送文字 完整代碼

          # 初始化瀏覽器 打開微博登錄頁面
          def init_browser():
              path=r'C:/MyEnv/chromedriver.exe '  # 指定驅動存放目錄
              ser=Service(path)
              chrome_options=webdriver.ChromeOptions()
              # 把允許提示這個彈窗關閉
              prefs={"profile.default_content_setting_values.notifications": 2}
              chrome_options.add_experimental_option("prefs", prefs)
              driver=webdriver.Chrome(service=ser, options=chrome_options)
              driver.maximize_window()    
              driver.get('https://weibo.com/login.php')
              return driver
              
              
          # 讀取cookies 登錄微博
          def login_weibo(driver):
              cookies=read_cookies()
              for cookie in cookies:
                  driver.add_cookie(cookie)
              time.sleep(3)
              driver.refresh()  # 刷新網頁
          
          # 發布微博
          def post_weibo(content, driver):
              time.sleep(5)
              weibo_content=driver.find_element_by_xpath('//*[ @id="homeWrap"]/div[1]/div/div[1]/div/textarea')
              weibo_content.send_keys(content)
              bt_push=driver.find_element_by_xpath('//*[@id="homeWrap"]/div[1]/div/div[4]/div/button')
              bt_push.click()  # 點擊發布
              time.sleep(5)
              driver.close()  # 關閉瀏覽器
          
              
          if __name__=='__main__':
              # cookie登錄微博
              driver=init_browser()
              login_weibo(driver)
              # 自動發微博
              content='今天的天氣真不錯~'
              post_weibo(content, driver)
          復制代碼

          拓展:檢測cookies有效性

          檢測方法:利用本地cookies向微博發送get請求,如果返回的頁面源碼中包含自己的微博昵稱,就說明cookies還有效,否則無效。

          # 檢測cookies的有效性
          def check_cookies():
              # 讀取本地cookies
              cookies=read_cookies()
              s=requests.Session()
              for cookie in cookies:
                  s.cookies.set(cookie['name'], cookie['value'])
              response=s.get("https://weibo.com")
              html_t=response.text
              # 檢測頁面是否包含我的微博用戶名
              if '老表max' in html_t:
                  return True
              else:
                  return False
          復制代碼

          拓展:定時每日自動發送

          可以參考上一篇文章:如何用Python發送告警通知到釘釘?

          包括如何設置守護進程,在上一篇文章中也有介紹。

          from apscheduler.schedulers.blocking import BlockingSchedulera
          
          '''
          每天早上9:00 發送一條微博
          '''
          def every_day_nine():
              # cookie登錄微博
              driver=init_browser()
              login_weibo(driver)
              req=requests.get('https://hitokoto.open.beeapi.cn/random')
              get_sentence=req.json()
              content=f'【每日一言】{get_sentence["data"]} 來自:一言api'
              # 自動發微博
              post_weibo(content, driver)
              
          
              
          # 選擇BlockingScheduler調度器
          sched=BlockingScheduler(timezone='Asia/Shanghai')
          
          # job_every_nine 每天早上9點運行一次  日常發送
          sched.add_job(every_day_nine, 'cron', hour=9)
          
          # 啟動定時任務
          sched.start()
          復制代碼

          下期預告

          凡是自動化的東西,都可以發抖服務器上持續的去跑,當然,本地電腦也可以進行學習使用。

          下一期,感覺有太多東西需要更新了,慢慢來吧,提前祝大家元旦快樂~2022,我準備好了!

          前端開發的快速迭代中,Parcel以零配置的優勢,為迅速搭建原型提供了極大的便利。相對于Vite,Parcel在輕量級項目和快速原型開發中更顯手腳敏捷。Vite更適合需要細致構建優化的復雜場景。Parcel的易用性讓開發者能立刻投入創意實現,無需任何配置。


          簡介

          以迅速和便利的特性贏得開發者好評的前端打包工具Parcel,可以無需過多調整設置,自動地處理JavaScript、CSS和HTML等各類資源。這種簡易性和高效性,使Parcel在GitHub中獲得了43k star。






          Parcel的特性

          • 快速打包 - 多核編譯,以及文件系統緩存,即使在重新啟動之后也能快速重新構建。
          • 支持JS,CSS,HTML,文件資源等- 不需要安裝任何插件。
          • 在需要的時候自動使用Babel,PostCSS和PostHTML自動轉換模塊 - 甚至是node_modules。
          • 零配置代碼拆分,使用動態import語句分割。
          • 內置支持模塊熱替換
          • 友好的錯誤記錄體驗,語法突出顯示的代碼幀有助于查明問題。


          為什么需要Parcel?

          目前已經有很多的打包工具了,包括webpack和browserify。那么為什么我們還需要另外一個呢?主要原因是因為開發者的經驗。

          許多的打包工具都是圍繞著配置和插件構建的,而且為了讓應用正常的工作,超過500行的配置并不罕見。這些配置不僅繁瑣而且耗時。通常情況下,這可能導致次優化的應用發送到生產環境。parcel被設計成零配置的:只需要將它指向應用程序的入口點,它就能正常工作。

          目前現存的打包工具都非常慢。擁有大量文件和依賴的大型應用可能需要花費幾分鐘的時間來構建,這在開發過程中隨著時間的變化而變得尤為痛苦。監聽文件變更能夠幫助重新構建,但初始的啟動仍然非常慢。parcel利用工作線程編譯你的代碼,利用現代的多核處理器能力。這導致了初始構建的速度大大提升。它還具有一個文件系統緩存,可以保存每一個文件的編譯結果,以便后續能夠更快的啟動。

          最后,現有的打包工具都是圍繞字符串加載/轉換構建的,其中轉換需要一個字符串,解析它,進行一些轉換,然后再次生成代碼。通常這樣會導致許多的解析和代碼生成在單個文件上運行,這是非常低效的。相反,parcel的轉換工作在AST上,因此每個文件只有一個解析,多個轉換以及一個代碼生成。


          Parcel如何工作的?

          parcel將資源樹轉換為bundle樹。許多其它的打包工具基本上都是基于js資源,其它格式都是粘貼的-例如,默認情況下以字符串的形式內嵌到js中。parcel是文件類型無關的-它可以按照你期望的方式與任何類型的資源一起工作,無需配置。

          parcel將一個入口點作為輸入,可以是任何類型的:JS文件,HTML,CSS,圖片等。在parcel中定義了各種資源類型,它們知道如何處理特定的資源類型。資源文件被解析,它的依賴關系被提取,并轉換成最終的編譯形式。這創建了一個資源樹。

          一旦資源樹被構建,資源就被放入一個bundle樹中。為入口資源創建一個bundle,并為動態導入的資源創建子bundle,這回導致代碼拆分的發生。當導入不同類型的資源的時候就會創建子bundle,例如如果你在js中導入css文件,它就會打包成對應js的兄弟bundle。如果一個資源需要多個bundle,它會被打包到最近的共同祖先,因此它不會被包含多次。


          開始使用Parcel

          首先,我們需要安裝 Parcel。確保您已經安裝了 Node.js,然后通過以下命令安裝 Parcel:

          接下來,讓我們創建一個簡單的 HTML 文件,命名為 index.html:

          創建一個 src 目錄,并在其中添加一個名為 index.js 的 JavaScript 文件:

          現在我們已經準備好運行 Parcel。在項目根目錄中,運行以下命令:

          Parcel 會自動處理所有相關的資源,并在瀏覽器中打開一個服務器。當您對源文件進行更改時,Parcel 會自動重新構建項目并刷新瀏覽器。


          配置Parcel

          盡管 Parcel 的一個主要優勢是零配置,但有時您可能需要根據項目需求進行一些自定義。要在 Parcel 中配置項目,您可以創建一個名為 .parcelrc 的文件,并在其中指定您的配置。

          例如,要更改輸出目錄,您可以在 .parcelrc 文件中添加以下內容:

          這將使 Parcel 將構建的資源輸出到名為 custom-dist 的目錄中。


          開源地址:點贊+轉發,關注,私信【Parcel


          主站蜘蛛池模板: 人妻AV一区二区三区精品 | 久久亚洲中文字幕精品一区四 | 美女免费视频一区二区三区| 国产福利电影一区二区三区,亚洲国模精品一区 | 中文字幕亚洲乱码熟女一区二区| 亚洲愉拍一区二区三区| 亚洲不卡av不卡一区二区| 在线免费一区二区| 无码少妇一区二区浪潮免费| 亚洲码一区二区三区| 国产精品毛片一区二区三区| 好湿好大硬得深一点动态图91精品福利一区二区 | 人妻少妇一区二区三区| 无码精品久久一区二区三区| 国精产品一区一区三区有限公司| 国产精品一区在线麻豆| 国产成人精品第一区二区| 亚洲一区二区三区久久久久| 一区二区三区亚洲| 乱精品一区字幕二区| 99精品一区二区三区| 国产91精品一区二区麻豆网站 | 欲色影视天天一区二区三区色香欲| 亚洲中文字幕乱码一区| 在线观看精品一区| 四虎一区二区成人免费影院网址 | 久久精品国产第一区二区| 国产福利电影一区二区三区,日韩伦理电影在线福 | 国产婷婷色一区二区三区| 国产成人无码一区二区三区| 国产在线一区二区三区| 午夜福利一区二区三区高清视频 | 中文字幕在线播放一区| 一本AV高清一区二区三区| 色偷偷一区二区无码视频| AV无码精品一区二区三区| 国产Av一区二区精品久久| 小泽玛丽无码视频一区| 国产日韩AV免费无码一区二区| 久久久久久人妻一区精品| 波多野结衣久久一区二区|