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 精品国产系列在线观看,天天操天天爱天天干,欧美成人免费高清视频

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Javascript基于模板生成PDF 文檔

          您的 js 應(yīng)用程序中使用 eDocGen 從 JSON/XML/Database 創(chuàng)建 PDF 文檔的指南。

          文檔生成是開發(fā)人員生活中非常普遍的需求。無論是電子商務(wù)網(wǎng)站、管理應(yīng)用程序還是其他任何東西。它可以是發(fā)票生成、保險(xiǎn)文件準(zhǔn)備、醫(yī)生處方、人力資源報(bào)價(jià)生成、工資單生成,你可以想到大量的用例??偸切枰晌臋n。

          從開發(fā)人員的角度來看,有幾種常見的方法可以完成這項(xiàng)工作。

          1. 創(chuàng)建 HTML 元素并打印它們以生成文檔
          2. 使用一些庫來生成文檔
          3. 讓服務(wù)器處理基于靜態(tài)模板的文檔生成

          這些方法對(duì)我沒有幫助。客戶希望自己定制他們的文件。我一直在尋找一種方法,發(fā)現(xiàn)eDocGen是一種單點(diǎn)解決方案。

          與其他服務(wù)不同,eDocGen 提供了可以集成到我們應(yīng)用程序中的 RestAPI。

          在本文中,我們將討論如何將 eDocGen 集成到我們的 js 應(yīng)用程序中,以從各種數(shù)據(jù)格式(如 JSON/XML/Database 模式)生成文檔。請(qǐng)免費(fèi)試用以開始編碼。

          讓我們潛入并編寫代碼。

          項(xiàng)目設(shè)置

          出于演示目的,我創(chuàng)建了一個(gè)在 nodejs 上運(yùn)行的示例 js 應(yīng)用程序。

          請(qǐng)按照以下步驟為我們?cè)O(shè)置編碼游樂場(chǎng)。

          步驟1:

          用于npm init創(chuàng)建 package.json

          第2步:

          添加axios, form-data, request,xhr2開發(fā)此應(yīng)用程序所需的依賴項(xiàng)npm install axios form-data request xhr2

          第 3 步:

          我們需要一個(gè)索引文件作為我們應(yīng)用程序的起點(diǎn)。在根目錄中創(chuàng)建一個(gè) index.js 文件并修改 package.json 如下所示。

          JSON

          scripts": {
              "start": "node index.js"
            }

          現(xiàn)在我們有一個(gè)基本的應(yīng)用程序可以開始。這些步驟結(jié)束后,package.json 應(yīng)該如下所示。

          JSON

          {
            "name": "nodejs-multiple-upload-files",
            "version": "1.0.0",
            "main": "index.js",
            "scripts": {
              "start": "node index.js"
            },
            "dependencies": {
              "axios": "^0.27.2",
              "form-data": "^4.0.0",
              "request": "^2.88.2",
              "xhr2": "^0.2.1"
            }
          }
          

          登錄

          雖然這篇文章是關(guān)于文檔生成的,但我們需要登錄才能獲取我們的訪問令牌。這是一個(gè)典型的JWT令牌,將用于授權(quán)文檔生成 API。

          JavaScript

          var XMLHttpRequest = require("xhr2");
          var xhr = new XMLHttpRequest();
          
          module.exports.getToken = function (callback) {
            var data = JSON.stringify({
              username: "<your username>",
              password: "<password>",
            });
          
            xhr.addEventListener("readystatechange", function () {
              if (this.readyState === 4) {
                token = JSON.parse(this.responseText).token;
          
                console.log("User Token", token);
                callback(token);
              }
            });
          
            xhr.open("POST", "https://app.edocgen.com/login");
            xhr.setRequestHeader("content-type", "application/json");
            xhr.setRequestHeader("cache-control", "no-cache");
            xhr.send(data);
          };
          

          我們可以將令牌在應(yīng)用程序中緩存一個(gè)小于過期時(shí)間的時(shí)間段,并使用它來生成文檔或上傳模板。到期時(shí)間過后,我們可以刷新令牌。緩存可以是 Redis 或內(nèi)存緩存。這取決于您的應(yīng)用程序設(shè)計(jì)。

          模板設(shè)計(jì)

          如上所述,eDocGen 允許用戶自定義和上傳模板。但是如何動(dòng)態(tài)映射數(shù)據(jù)呢?有一些將數(shù)據(jù)映射到文檔的規(guī)則。我們將看到如何使用規(guī)則創(chuàng)建模板。

          看看這個(gè)文件。

          eDocGen{}對(duì)動(dòng)態(tài)字段使用由 括起來的標(biāo)簽。我們可以動(dòng)態(tài)添加文字、logo、表格、條件語句、數(shù)學(xué)計(jì)算等。

          例如,在上圖中,

          字符串字段: {Invoice_Number}{Invoice_Date}配置為替換為模板中的文本。模板中 {} 內(nèi)的任何內(nèi)容都將與輸入數(shù)據(jù)匹配并替換。

          動(dòng)態(tài)表: 當(dāng)表中存在需要循環(huán)和替換的數(shù)據(jù)數(shù)組時(shí),動(dòng)態(tài)表將是一個(gè)不錯(cuò)的選擇。表中的行以 開頭{#tablename}和結(jié)尾{/tablename}。在上面的示例中,發(fā)票表中的一行在第一列以 {#IT} 開頭,在最后一列以 {/IT} 結(jié)尾。行中的列可以有字符串字段。在我們的示例中,{Item_description}并且{Amount}

          圖片: eDocGen 提供動(dòng)態(tài)添加圖片到模板的功能。請(qǐng)按照以下步驟操作。

          • 將圖像上傳到應(yīng)以 image_id 響應(yīng)的 eDogGen。
          • {%image_id}是用于填充圖像的標(biāo)簽。圖像image_id將從 eDocGen 存儲(chǔ)中獲取并替換為{%image_id}. 預(yù)計(jì)image_id將出現(xiàn)在輸入數(shù)據(jù)中。

          基于條件的動(dòng)態(tài)字段(If-Else):可以使用條件標(biāo)簽有條件地顯示內(nèi)容。例如,當(dāng)語言為英語時(shí),文檔中會(huì)顯示{#language == "english"} 英語內(nèi)容。同樣,單個(gè)文檔模板可以支持多種語言。

          數(shù)學(xué)計(jì)算: eDocGen 支持基于模板中定義的公式的數(shù)學(xué)計(jì)算??梢允褂靡韵鹿接?jì)算發(fā)票中項(xiàng)目金額的總和。

          JSON

          {
              IT // array of items
              | summation:'Amount' // value that needs to be used for calculation 
              | format_number: ",” // format of the value
          }

          請(qǐng)前往JSON-to-pdf了解更多詳情。

          模板上傳

          準(zhǔn)備好模板后,就可以將其上傳以供使用。有兩種方法。

          1. eDocGen 的交互式 UI - 與 Dropbox、驅(qū)動(dòng)器、Evernote 集成
          2. eDocGen 的 RestAPI - 可以集成到客戶端代碼中以上傳模板。

          對(duì)于演示,我使用 UI 來上傳模板。成功上傳后,我們會(huì)得到一個(gè) ID 作為響應(yīng)。這是將用于生成文檔的 ID。

          如果您希望使用 API,請(qǐng)?jiān)诖颂幜粝?Upload API 結(jié)構(gòu)供您參考。

          JSON

          
          "/api/v1/document": {
            "post": {
              "tags": [
                "Document"
              ],
              "description": "Upload template to eDocGen",
              "produces": [
                "application/json"
              ],
              "consumes": [
                "multipart/form-data"
              ],
              "parameters": [
                {
                  "name": "documentFile",
                  "description": "file to upload",
                  "required": true,
                  "type": "file",
                  "in": "formData"
                },
                {
                  "name": "x-access-token",
                  "in": "header",
                  "description": "JWT auth token from login",
                  "required": true,
                  "type": "string"
                }
              ],
              "responses": {
                "200": {
                  "description": "Successfully uploaded document file"
                },
                "other": {
                  "description": "Operation failed"
                }
              }
            }
          }

          JSON 到文檔生成

          現(xiàn)在我們準(zhǔn)備好了模板。讓我們生成文檔。

          文檔生成有兩個(gè)階段。

          1. 請(qǐng)求生成文檔
          2. 下載文件

          第 1 步:請(qǐng)求生成文檔

          我們要求生成包含所需詳細(xì)信息的文檔,并得到確認(rèn)。該過程異步發(fā)生在屏幕后面。

          文檔生成所需的參數(shù)

          應(yīng)用程序接口:POST-/api/v1/document/generate/bulk

          請(qǐng)求正文

          表格數(shù)據(jù)

          文檔 ID

          模板的id

          格式

          pdf/docx(模板應(yīng)支持格式)

          輸出文件名

          輸出文件的文件名。

          輸入文件

          該文件包含標(biāo)記值。支持 json、xlsx 和 xml。

          標(biāo)題

          內(nèi)容類型

          多部分/表單數(shù)據(jù)

          x-訪問令牌

          來自登錄的 JWT 身份驗(yàn)證令牌

          輸入數(shù)據(jù)

          inputFile 中的數(shù)據(jù)應(yīng)該是模板定義的結(jié)構(gòu)。例如,對(duì)于上面的模板映射將如下所示。

          • Invoice_Number在 JSON 中應(yīng)該與{Invoice_Number}模板中的匹配。
          • 對(duì)于表數(shù)據(jù),它應(yīng)該是一個(gè)對(duì)象數(shù)組,帶有Item_DescriptionAmount.
          • 金額應(yīng)該是一個(gè)用于求和計(jì)算的數(shù)字。

          第 2 步:下載文件

          可以使用從上述步驟中獲得的輸出 ID 和輸出文件的名稱下載生成的文檔。

          我們將在這里使用兩個(gè) API。

          1. 了解文件存在的 API:/api/v1/output/name/${fileName}
          2. 下載文件的API:/api/v1/output/download/${outputId}

          由于文檔生成是異步發(fā)生的,要知道文檔是否生成,我們將使用/api/v1/output/nameapi。

          來自 API 的成功響應(yīng)/api/v1/output/name將下載文件。

          我將這兩個(gè)步驟組合在一個(gè) js 文件中,如下所示。

          爪哇

          let login = require("../edocgen_login");
          const fs = require("fs");
          const uuid = require("uuid");
          const FormData = require("form-data");
          let axios = require("axios");
          let fileName = uuid.v4();
          const headers = {
            "Content-Type": "multipart/form-data",
            "x-access-token": "null",
          };
          
          const hostName = "https://app.edocgen.com/api/v1/document/generate/bulk";
          
          
          const outputFormat = "<format>";// pdf / docx
          const documentId = "<template_id>";    // id of the template we want to use
          
          module.exports.generateFiles =  function () {
            let authToken = login.getToken(function handleUsersList(token) {
          
              headers["x-access-token"] = token;
          
              var formBody = new FormData();
              formBody.append("documentId", documentId);
              formBody.append("format", outputFormat);
              formBody.append("outputFileName", fileName);
              // json data for the template
              formBody.append("inputFile", fs.createReadStream("./JSON_Data_Single.json"));   // local path forjson file
          
              let config = {
                method: "post",
                url: hostName,
                headers: headers,
                data: formBody,
              };
          
              console.log(`https://app.edocgen.com/api/v1/output/name/${fileName}.${outputFormat}`);
              let config_output = {
                method: "get",
                url:`https://app.edocgen.com/api/v1/output/name/${fileName}.${outputFormat}`,
                headers: headers,
              };
          
              const MAX_RETRY = 50;
              let currentRetry = 0;
          
              // max retry for 50 times
              function errorHandler() {
                if (currentRetry < MAX_RETRY) {
                  currentRetry++;
                  console.log("Document is not prepared yet! Retrying...");
                  sendWithRetry(processResponse);
                } else {
                  console.log("No luck. Document is not generated. Retried multiple times.");
                }
              }
              
              // sendWithRetry checks for file existence
              // on success, it proceeds to download the file
              // on failure, it retries 
              // todo: introduce spin lock
              function sendWithRetry(callback) {
                axios(config_output)
                  .then(function (response) {
                    if (response.data.output.length !== 1) {
                      throw new axios.Cancel("Document is not found. Throw error.");
                    } else {
                      callback(response);
                    }
                  })
                  .catch(errorHandler);
              }
          
              axios(config)
                .then(function (response) {
                  sendWithRetry(processResponse);
                })
                .catch(function (error) {
                  console.log(error);
                });
            });
          };
          
          function processResponse(response) {
            const outputId = response.data.output[0]._id;
            console.log(
              "Output Document is Generated. Id = ",
              response.data.output[0]._id
            );
          
            let config_download = {
              method: "get",
              url: `https://app.edocgen.com/api/v1/output/download/${outputId}`,
              headers: headers,
              responseType: "arraybuffer",
          
            };
          
            axios(config_download)
              .then(function (response) {
                console.log("Output file is downloaded " + `${fileName}.${outputFormat}`);
                fs.writeFileSync(`./${fileName}.${outputFormat}`, response.data);
              })
              .catch(function (error) {
                console.log("Error while downloading");
                console.log(error);
              });
          }
          

          單個(gè)與多個(gè)文檔

          當(dāng)數(shù)據(jù)為單個(gè) JSON 時(shí),將生成給定格式的單個(gè)文檔。

          當(dāng)數(shù)據(jù)是對(duì)象數(shù)組時(shí),將生成每個(gè)數(shù)組元素的文檔并將其壓縮到文件中。

          XML 到文檔生成

          XML 數(shù)據(jù)的過程很簡(jiǎn)單。我們需要做的就是傳遞 XML 文件來代替 JSON 數(shù)據(jù)。

          就像JSON to document,XML to Document 我們也需要documentId, outputFileName, format and inputFile。除輸入文件外,與 JSON 相同的所有內(nèi)容都將是 XML 文件。

          示例 XML 數(shù)據(jù)如下所示

          XML

          <?xml version="1.0" encoding="UTF-8" ?>
          <marker>
            <values>
              <Invoice_Number>SBU-2053501</Invoice_Number>
              <Invoice_Date>31-07-2020</Invoice_Date>
              <Terms_Payment>Net 15</Terms_Payment>
              <Company_Name>ABC company</Company_Name>
              <Billing_Contact>ABC-Contact1</Billing_Contact>
              <Address>New york, United State</Address>
              <Email>support@edocgen.com</Email>
          	<Logo>621cd2b783a6095d7b15a443</Logo> 
               <Sum1>6,751</Sum1>
          	 <para>61b334ee7c00363e11da3439</para>
              <ITH>
                <Heading1>Item Description</Heading1>
                <Heading2>Amount</Heading2>
              </ITH>
              <IT>
                <Item_Description>Product Fees: X</Item_Description>
                <Amount>5,000</Amount>
              </IT>
            </values>
          <marker>

          我為 XML 作為數(shù)據(jù)源所做的代碼更改很簡(jiǎn)單,如下所示

          JavaScript

          var formBody = new FormData();
          formBody.append("documentId", documentId);
          formBody.append("format", outputFormat);
          formBody.append("outputFileName", fileName);
          formBody.append("inputFile", fs.createReadStream("./XML_Invoice.xml"));

          數(shù)據(jù)庫到文檔生成

          從數(shù)據(jù)庫生成文檔幾乎與其他數(shù)據(jù)源相同。但在這種情況下,我們需要提供連接詳細(xì)信息和 SQL 查詢,而不是上傳 inputFile。

          SQL 查詢的輸出列應(yīng)與文檔模板中的標(biāo)簽匹配。

          讓我們看看如何在代碼中進(jìn)行配置。

          JavaScript

          const templateId = "<template id>";
          const dbVendor = "mysql";
          const dbUrl = "<jdbc connection URL>";
          const dbLimit = "100";
          const dbPassword = "<database password>";
          const dbQuery = "SELECT JSON_ARRAY(first, last) FROM customers;";
          const outputFormat = "pdf";
          
          // form data prepareation
          let formBody = new FormData();
          formBody.append("documentId", templateId);
          formBody.append("format", outputFormat);
          formBody.append("dbVendor", dbVendor);
          formBody.append("dbUrl", dbUrl);
          formBody.append("dbLimit", dbLimit);
          formBody.append("dbPassword", dbPassword);
          formBody.append("dbQuery", dbQuery);
          formBody.append("outputFileName", fileName);

          其他一切都將保持不變。

          通過電子郵件發(fā)送文檔

          eDocGen 提供了通過電子郵件發(fā)送生成的文檔的功能。

          文檔生成所需的參數(shù)

          應(yīng)用程序接口:POST-/api/v1/output/email

          請(qǐng)求正文

          JSON

          出局

          將需要通過電子郵件發(fā)送的輸出 ID 放在這里

          電子郵件ID

          將用戶電子郵件放在這里

          標(biāo)題

          內(nèi)容類型

          多部分/表單數(shù)據(jù)

          x-訪問令牌

          來自登錄的 JWT 身份驗(yàn)證令牌

          代碼示例

          let login = require("../edocgen_login");
          let axios = require("axios");
          const hostName = "https://app.edocgen.com/api/v1/output/email";
          const headers = {
            "Content-Type": "application/json",
            "x-access-token": "null",
          };
          
          const outId = "<output ID>"; // Put output ID here which need to be sent via email
          const emailId = "<user email>"; // Put user email here
          
          module.exports.generateFiles = function () {
            let authToken = login.getToken(function handleUsersList(token) {
              headers["x-access-token"] = token;
          
              let payload = { outId: outId, emailId: emailId };
              let config = {
                method: "post",
                url: hostName,
                headers: headers,
                data: payload,
              };
          
              axios(config)
                .then(function (response) {
                  console.log("Mail sent");
                })
                .catch(function (error) {
                  console.log(error);
                });
            });
          };
          

          來自 eDocGen 的電子郵件如下所示

          還有很多其他的功能我在這里無法涵蓋。但我希望這篇文章可以為您提供一個(gè)從哪里開始的想法。

          前一陣兒被某網(wǎng)站的 JS 反爬流程難住了,至今也沒明白它的反扒原理和攻破方法。最終找到了一個(gè)自動(dòng)化腳本工具 autoit 3,用一個(gè)笨方法將人手動(dòng)點(diǎn)擊瀏覽器的動(dòng)作腳本化,達(dá)到網(wǎng)頁數(shù)據(jù)獲取目的,拿到網(wǎng)頁文件后,再用代碼解析,曲線完成任務(wù)。

          本文將介紹這個(gè)自動(dòng)化的過程,并帶編寫一個(gè)完整的 autoit 3 爬蟲腳本,希望對(duì)各位讀者朋友有所啟發(fā)。

          自動(dòng)化操作分析

          以國(guó)家信息安全漏洞共享平臺(tái)為例,它在返回?cái)?shù)據(jù)前發(fā)起了兩次 512 響應(yīng),第三次瀏覽器帶著動(dòng)態(tài)生成的 Cookie 信息才能得到數(shù)據(jù)。

          這次咱們直接從網(wǎng)頁入手,操作鍵盤找到“下一頁” 按鈕,按下 Enter 鍵完全請(qǐng)求。通過鍵盤定位到 “下頁” 按鈕的過程為:

          1. 第一步,按下 “End” 鍵,到達(dá)網(wǎng)頁底部;
          2. 第二步,反向 “Tab” 鍵,按 15 次就可定位到 “下頁” 按鈕。

          接著就可以編寫自動(dòng)化腳本了,把剛剛的手動(dòng)操作翻譯成腳本命令:

          1. 切換為英文輸入法,保證瀏覽器輸入欄信息正確;
          2. 打開 Chrome 瀏覽器;
          3. 向?yàn)g覽器地址欄輸入目標(biāo) URL;
          4. 按下 Enter 鍵,等待 2 秒保證頁面數(shù)據(jù)加載完成;
          5. 按下 Ctrl +S 鍵,并向存儲(chǔ)路徑發(fā)送存儲(chǔ)文件名稱,等待“保存”操作完成;
          6. 按下 End 鍵盤,定位到頁面底部;
          7. 按下反向 Tab 鍵 15 次,定位到 “下頁” 按鈕;
          8. 按下 Enter 鍵,請(qǐng)求下一頁數(shù)據(jù);
          9. 循環(huán) 5-8 這個(gè)過程 N 次,N=需要爬的頁數(shù)。

          這個(gè)流程,對(duì)其他高反扒的信息發(fā)布網(wǎng)站,也是適用的。

          編寫自動(dòng)化腳本

          按照上面的流程,編寫 autoit 自動(dòng)化腳本,創(chuàng)建一個(gè) myspider.au3 文件:

          #include <AutoItConstants.au3>
          
          ;;切換為英文輸入法,保證瀏覽器輸入正常
          $hWnd = WinGetHandle("[ACTIVE]");$hWnd 為目標(biāo)窗口句柄,這里設(shè)置的是當(dāng)前活動(dòng)窗口
          $ret = DllCall("user32.dll", "long", "LoadKeyboardLayout", "str", "08040804", "int", 1 + 0)
          DllCall("user32.dll", "ptr", "SendMessage", "hwnd", $hWnd, "int", 0x50, "int", 1, "int", $ret[0])
          
          $url = "https://www.cnvd.org.cn/flaw/list.htm"
          spiderData($url)
          
          Func spiderData($url)
          	;;打開 Chrome 瀏覽器窗口
          	$chromePath = "C:\Users\admin\AppData\Local\Google\Chrome\Application\chrome.exe"
          	Run($chromePath)
          
          	;;登錄窗口顯示
          	WinWaitActive("[CLASS:Chrome_WidgetWin_1]")
          	;; 休息2000毫秒
          	Sleep(2000)
          	;; 移動(dòng)窗口
          	WinMove("[CLASS:Chrome_WidgetWin_1]", "打開新的標(biāo)簽頁 - Google Chrome", 0, 0,1200,740,2)
          
          	;; 休息500毫秒
          	Sleep(500)
          
          	;;地址欄輸入U(xiǎn)RL 并按下 Enter 鍵
          	Send($url)
          	Sleep(500)
          	Send("{enter}")
          	Sleep(3000)
          
          	;; 循環(huán)爬取需要的頁數(shù),測(cè)試只爬3頁
          	For $i = 1 To 3 Step 1
          		;;打開右鍵另存為按鈕: Ctrl+S
          		send("^s")
          		Sleep(2000)
          		WinWait("[CLASS:#32770]","",10)
          
          		;;將存儲(chǔ)路徑設(shè)置到另存為組件輸入框 Edit1 里
          		$timeNow = @YEAR & "" & @MON & "" & @MDAY & "" & @HOUR & "" & @MIN
          		$savePath = "F:\A2021Study\ListData\" &$timeNow &  "_page" & $i & ".html"
          		ControlSetText("另存為","", "Edit1", $savePath)
          
          		;;點(diǎn)擊確定
          		ControlClick("另存為","","Button2")
          
          		;;再次確定
          		WinWait("[CLASS:#32770]","",10)
          		ControlClick("確認(rèn)另存為","","Button1")
          
          		;; 等待保存操作完成
          		Sleep(3000)
          
          		;; 定位到下一頁按鈕,并觸發(fā)點(diǎn)擊下一頁
          		send("{END}")
          		Send("+{TAB 15}")
          		Send("{enter}")
          
          		;;點(diǎn)擊確定后,等待網(wǎng)頁加載完成
          		Sleep(3000)
          	Next
          
          	;; 整個(gè)操作完成,則關(guān)閉瀏覽器
          	Send("^w")
          EndFunc

          腳本編寫過程中,有幾點(diǎn)需要注意:

          • 第一,輸入法切換很重要,否則 URL 地址欄的值很容易亂;
          • 第二, windows 的文件路徑是反斜杠 \ ,否則會(huì)導(dǎo)致另存為的路徑無法識(shí)別;
          • 第三,幫助文檔里面提供的關(guān)閉方法是 WinClose ,但是反復(fù)測(cè)試,確定這個(gè)方法不靠譜,要么會(huì)引起瀏覽器異常關(guān)閉導(dǎo)致下次打開會(huì)恢復(fù)上次的網(wǎng)址;要么完全不生效。迂回的解決辦法是用關(guān)閉按鍵 Ctrl+W ,完成了正常關(guān)閉的目的。

          因?yàn)榕老x要作為定時(shí)任務(wù)運(yùn)行的,為避免打開太多瀏覽器窗口,因此需要在腳本結(jié)束時(shí)關(guān)閉瀏覽器。

          啟示錄

          數(shù)據(jù)爬取一般分為列表頁和詳情頁,定位點(diǎn)擊每一條詳情的過程比較麻煩,所以爬取詳情頁面的和列表分開,用 Java 代碼解析所有詳情 URL 后,再由另一個(gè) autoit 腳本去獲取詳情頁面,這個(gè)流程大家可以自己寫一下,這里就不詳細(xì)介紹了。

          最后再匯總下整個(gè)爬取的流程:

          第一步,執(zhí)行爬取列表的 autoit 腳本,得到列表頁面 html;
          第二步,解析列表頁 html ,得到所有詳情頁面的 URL ,寫入到文件中;
          第三步,執(zhí)行爬取詳情頁面的 autoit 腳本,它遍歷第二步的目標(biāo) URL ,得到詳情頁 html ;
          第四步,解析詳情頁 html 文件,得到詳情數(shù)據(jù)。
          

          總控流程、第二步和第四步的解析都用 Java 代碼完成,用 Runtime.getRuntime().exec("cmd /c E:\A2021Study\Autoit3\myspider.au3") 調(diào)用腳本,文件路徑是反斜杠。

          這個(gè)方法雖然有點(diǎn)笨,但完全是人工操作瀏覽器,能夠?qū)狗磁老x策略,感興趣的朋友可以執(zhí)行下本文的腳本試試。

          autoit 還是蠻有意思的,語法也很簡(jiǎn)單,DirCreate 創(chuàng)建文件,iniread 讀取配置項(xiàng),一行代碼頂 Java 幾十行,不得不承認(rèn) Java 操作文件才是最麻煩的哇!

          :如何用 JS 一次獲取 HTML 表單的所有字段 ?

          考慮一個(gè)簡(jiǎn)單的 HTML 表單,用于將任務(wù)保存在待辦事項(xiàng)列表中:

            <form>
              <label for="name">用戶名</label>
              <input type="text" id="name" name="name" required>
          
              <label for="description">簡(jiǎn)介</label>
              <input type="text" id="description" name="description" required>
          
              <label for="task">任務(wù)</label>
              <textarea id="task" name="task" required></textarea>
          
              <button type="submit">提交</button>
            </form>
          

          上面每個(gè)字段都有對(duì)應(yīng)的的type,ID和 name屬性,以及相關(guān)聯(lián)的label。用戶單擊“提交”按鈕后,我們?nèi)绾螐拇吮韱沃蝎@取所有數(shù)據(jù)?

          有兩種方法:一種是用黑科技,另一種是更清潔,也是最常用的方法。為了演示這種方法,我們先創(chuàng)建form.js,并引入文件中。

          從事件 target 獲取表單字段

          首先,我們?cè)诒韱紊蠟镾ubmit事件注冊(cè)一個(gè)事件偵聽器,以停止默認(rèn)行為(它們將數(shù)據(jù)發(fā)送到后端)。

          然后,使用this.elements或event.target.elements訪問表單字段:

          相反,如果需要響應(yīng)某些用戶交互而動(dòng)態(tài)添加更多字段,那么我們需要使用FormData。

          使用 FormData

          首先,我們?cè)诒韱紊蠟閟ubmit事件注冊(cè)一個(gè)事件偵聽器,以停止默認(rèn)行為。接著,我們從表單構(gòu)建一個(gè)FormData對(duì)象:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
          });
          

          除了append()、delete()、get()、set()之外,F(xiàn)ormData 還實(shí)現(xiàn)了Symbol.iterator。這意味著它可以用for...of 遍歷:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
          
            for (const formElement of formData) {
              console.log(formElement);
            }
          })
          

          除了上述方法之外,entries()方法獲取表單對(duì)象形式:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
            const entries = formData.entries();
            const data = Object.fromEntries(entries);
          });
          

          這也適合Object.fromEntries() (ECMAScript 2019)

          為什么這有用?如下所示:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
            const entries = formData.entries();
            const data = Object.fromEntries(entries);
          
            // send out to a REST API
            fetch("https://some.endpoint.dev", {
              method: "POST",
              body: JSON.stringify(data),
              headers: {
                "Content-Type": "application/json"
              }
            })
              .then(/**/)
              .catch(/**/);
          });
          

          一旦有了對(duì)象,就可以使用fetch發(fā)送有效負(fù)載。

          小心:如果在表單字段上省略name屬性,那么在FormData對(duì)象中剛沒有生成。

          總結(jié)

          要從HTML表單中獲取所有字段,可以使用:

          • this.elements或event.target.elements,只有在預(yù)先知道所有字段并且它們保持穩(wěn)定的情況下,才能使用。

          使用FormData構(gòu)建具有所有字段的對(duì)象,之后可以轉(zhuǎn)換,更新或?qū)⑵浒l(fā)送到遠(yuǎn)程API。*


          作者:VALENTINO GAGLIARDI 譯者:前端小智 來源:valentinog

          原文:https://www.valentinog.com/blog/form-data/


          主站蜘蛛池模板: 伊人久久大香线蕉av一区| 久久国产精品视频一区| 亚洲AV无码一区二区二三区入口 | 少妇无码一区二区三区| 中文字幕一区二区三区久久网站| 亚洲视频在线一区| 国产亚洲情侣一区二区无| 国产亚洲日韩一区二区三区| 精品国产日产一区二区三区| 亚洲综合无码精品一区二区三区| 日本高清天码一区在线播放| 国产经典一区二区三区蜜芽| 亚洲一区免费观看| 亚洲av综合av一区| 久久国产精品亚洲一区二区| 麻豆视频一区二区三区| 日本在线视频一区二区三区| 国产精品久久久久一区二区三区| 2021国产精品视频一区| 国产一区二区成人| 国产乱码精品一区二区三区| 日韩在线一区高清在线| 国模大胆一区二区三区| 国产在线不卡一区| 精品一区二区三区中文| 国产福利在线观看一区二区 | 亚洲一区二区三区写真| 国产电影一区二区| 国产91精品一区二区麻豆网站| 91在线精品亚洲一区二区| 91一区二区三区四区五区| 国产伦精品一区二区三区女| 一本一道波多野结衣AV一区| 怡红院美国分院一区二区| 国产日韩综合一区二区性色AV| 一区二区三区免费视频网站| 亚洲日本一区二区三区在线不卡 | 国产av一区最新精品| 国产成人免费一区二区三区| 一区二区三区电影网| 亚洲一区二区三区偷拍女厕|