整合營銷服務商

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

          免費咨詢熱線:

          僅使用 01 提示使用 ChatGPT 代碼解釋器進行網頁抓取(分步教程)

          論您是否具有編程知識,執行網頁抓取似乎是一項復雜且要求苛刻的任務。但是,ChatGPT 和代碼解釋器插件將為我們節省許多代碼行和麻煩,因為它只需一個提示即可在幾秒鐘內從網頁中提取信息。

          接下來,我們將通過三個示例看到如何使用 ChatGPT 以簡單實用的方式執行網頁抓取,所有這些都是一步一步解釋的

          讓我們開始...\

          1) 沃爾瑪

          我們將使用沃爾瑪在線商店的“購買所有返校”部分。我在下面提供直接鏈接:

          在返校 - Walmart.com 中購買所有返校產品

          在“返校”中購買所有返校商店。購買產品,如 JLab 音頻 JBuddies 工作室兒童貼耳式...

          www.walmart.com

          步驟 1:定義要提取的字段

          我們需要定義我們希望提取的信息。這非常重要,因為它將幫助我們以后在 ChatGPT 中構建我們的提示

          在這種情況下,我們將抓取產品名稱和價格

          第 2 步:檢查代碼

          在這里,我們需要定義 1 個產品的代碼(作為示例,然后將其輸入到 ChatGPT 中)

          但在我們這樣做之前,請記住以下幾點:

          要訪問 Chrome 中的檢查元素功能,如果您使用的是 Windows,則有兩個鍵盤快捷鍵選項:

          a) 按 + 移位 + c

          b) 按 + 移位 + i

          如果您使用的是 macOS,請使用:

          a) alt + Command + i

          b) 選項 + 命令 + i

          考慮到這一點,我們現在可以檢查沃爾瑪網站。讓我們回顧一下以下部分:

          i) 產品名稱

          在這種情況下,我們需要在代碼中找到產品名稱進行抓取

          讓我們復制它,然后將其包含在我們的提示中。要復制 span 標簽\,我們將鼠標懸停在該部分上,右鍵單擊,將出現以下內容:

          現在我們只是復制它,出于實際目的,我們將保留它方便,以便稍后包含在提示中

          任天堂兒童超級馬里奧兄弟馬里奧世界17“筆記本電腦背包

          ii ) 價格

          我們將對價格字段執行相同的操作

          我們將保留價格字段的復制元素供以后使用

          .92

          如果您需要從網頁中提取更多部分,則應重復我們對產品名稱和價格執行的相同步驟

          提示:\要在代碼區域內快速找到要檢查的字段,只需將鼠標放在字段上,單擊鼠標右鍵,即可啟用檢查選項。

          步驟 3:保存 HTML 文件

          由于我們將使用代碼解釋器,因此我們需要向其附加一個文件。因此,我們要做的是將要抓取的頁面另存為HTML文件。

          返回頁面并使用鍵盤快捷鍵 Ctrl + S(適用于 Windows 和 macOS)

          鍵盤快捷鍵:按 Ctrl + s

          接下來,將文件以 HTML 格式保存在本地文件夾中

          第 4 步:上傳 HTML 文件 + 生成提示

          現在我們已經在 Web 上定義了要抓取的字段及其代碼,讓我們在 ChatGPT 中構造提示

          如果您尚未激活代碼解釋器,讓我們按照一些說明進行操作。否則,我建議您跳過此部分,直接進入構造提示

          i) 設置

          ii ) 打開代碼解釋器

          ChatGPT 中激活代碼解釋器后,讓我們上傳我們在步驟 3 中保存的 HTML 文件

          現在,讓我們構建提示,同時考慮產品名稱和價格,以及每個部分的代碼(如有疑問,請查看步驟 2)

          提示:從HTML文件中,提取產品名稱和價格,將數據放在表格上并導出為CSV文件

          這是一個產品的元素: 任天堂兒童超級馬里奧兄弟馬里奧世界17“筆記本電腦背包

          以下是價格的要素:

          .92

          如果缺少產品價格,請將該價格保留為空數據

          在提示中,我們看到有 04 個部分

          在第一段中,我指定我已經加載了一個 HTML 文件,并要求它抓取產品名稱和價格。完成此操作后,我請求它將數據導出到CSV文件中

          在第二段和第三段中,我向 ChatGPT 提供了產品名稱和價格字段的每個相應結構的示例。我們看到每個產品都是一個跨度\標簽,價格是一個 div 標簽\

          在 last 段落中,如果它找到價格的空值,我要求它分配空\數據

          請務必牢記此提示,因為即將推出的示例將具有相同的結構,并且只會更改字段及其代碼

          結果:

          下載并打開 CSV\ 文件

          最后,我們成功地對產品及其各自的價格進行了網絡抓取,然后將其導出為CSV文件,如表格圖像所示。請注意,我們用作示例的產品包括在內!

          獎金

          前面的步驟使我們能夠從沃爾瑪網站的第一(01)頁執行網絡抓取。但是,如果我們想從第二個 (02) 頁面中提取數據,我們執行與前面相同的步驟,但不要忘記在此新頁面中識別產品并將其作為示例包含在提示中

          沃爾瑪網站上“返校”部分的第02頁

          i) 產品名稱

          Minecraft Boys Cliff Goats 圖形 T 恤,2 件裝,尺碼 4–18</跨度>

          ii) 價格

          .96

          就像第一頁一樣,我們需要將第二(02)頁的文件保存為HTML\格式(如果您有任何疑問,請查看步驟03)

          提示

          從HTML文件中,提取產品和價格的名稱,將數據放在表格上并將其導出為CSV文件。

          這是一個產品的元素: Minecraft Boys Cliff Goats 圖形 T 恤,2 件裝,尺碼 4–18</跨度>

          以下是價格的要素:

          .96

          如果缺少產品價格,請將該價格保留為空數據

          如果您希望將兩個表合并為一個,您可以要求 ChatGPT 執行以下操作:

          2. 目標

          在第二個示例中,我們將從目標網站的手機部分執行網頁抓取。我們將直接繼續,如果有任何疑問,請參閱沃爾瑪的第一個示例的步驟

          這是直接鏈接:

          手機 : 目標

          購買目標手機,你會喜歡的手機,價格低廉。選擇當日送貨,開車或訂購取貨...

          www.target.com

          步驟 1:讓我們確定要提取的字段

          a) 產品 b) 品牌 c) 價格

          現在,讓我們檢查每個目標字段的代碼級別(查看步驟 2)

          用于檢查的鍵盤快捷鍵:Ctrl + Shift + cWindows) 或 Alt + Command + imacOS)

          步驟 2:檢查代碼

          i) 產品

          我們找到代碼和標簽。我們復制并保留代碼,以便以后將其合并到 ChatGPT 提示符中(如有疑問,請查看第一個沃爾瑪示例的步驟 02)

          Tracfone Prepaid Apple iPhone SE 2nd Gen (64GB) CDMA — Black

          ii) 品牌

          Apple

          iii) 價格

          9.99

          步驟 3:保存 HTML 文件

          將要抓取的頁面另存為 HTML 文件(查看沃爾瑪示例中的步驟 3

          第 4 步:上傳 HTML 文件 + 生成提示

          我們將構造提示,但與前面的示例不同,我們將包括手機品牌字段(請參閱沃爾瑪示例的步驟 4)。

          加載 HTML 文件并為每個要抓取的字段添加代碼(產品名稱、品牌和價格)

          提示: 從HTML文件中,提取產品名稱,品牌,價格,將數據放在表格上并導出為CSV文件。提取所有產品

          這是一個產品的元素: Tracfone Prepaid Apple iPhone SE 2nd Gen (64GB) CDMA — Black

          以下是品牌的元素: Apple

          以下是價格的元素:

          9.99

          如果缺少產品價格,請將該價格保留為空數據

          結果

          下載并打開 CSV\ 文件

          結果很棒,我們能夠從 Target 網站抓取所有數據

          3) 亞馬遜

          在最后一個示例中,我們將對 Kindle 書籍執行網頁抓取。看看哪些書最受歡迎,然后使用 ChatGPT 創建具有不同趨勢主題的故事可能會很有趣

          這是鏈接:

          Amazon.com : 電子書點燃

          回到學校 殘疾客戶支持 關閉到大學診所 暢銷書 客戶服務 亞馬遜基礎知識 音樂...

          www.amazon.com

          步驟1:讓我們確定要提取的字段

          a) 產品或標題 b) 作者 c) 價格

          步驟 2:檢查代碼

          i) 產品或標題:

          我們找到代碼和標簽。我們復制并保留代碼,以便稍后將其合并到 ChatGPT 提示符中(如有疑問,請查看第一個沃爾瑪示例的步驟 02)

          要檢查的鍵盤快捷鍵是:Ctrl + Shift + cWindows)或Alt + Command + imacOS)。您可以參考步驟 2 了解更多詳情

          Lessons in Chemistry: A Novel

          ii ) 作者

          邦妮·加莫斯

          iii) 價格

          請注意,對于此示例,我們只會提取價格的整數部分

          14.

          步驟 3:保存 HTML 文件

          我們將要抓取的網頁保存為 HTML 文件。為此,我們使用快捷鍵 Ctrl + S 在我們要保存的頁面上。我們不要忘記將文件保存為 HTML 格式(檢查沃爾瑪示例的步驟 3 中的詳細信息)

          第 4 步:上傳 HTML 文件 + 生成提示

          現在,讓我們根據我們要從亞馬遜網頁中提取的字段來構建提示,特別是從他們的 Kindle 書籍部分。在本例中,我們要提取標題、作者和價格。

          接下來,我們加載 HTML 文件并添加代碼以抓取每個所需的字段(標題、作者和價格\))

          提示: 從HTML文件中,提取產品名稱、作者和價格,將數據放在表格上并導出為CSV文件。

          這是一個產品的元素: Lessons in Chemistry: A Novel

          以下是作者的元素: Bonnie Garmus

          以下是價格元素: 14.

          如果缺少產品價格,請將該價格保留為空數據

          讓我們看到我們看到的示例中的提示具有相同的結構

          結果

          我們下載 CSV\ 文件

          我們成功了!

          總結和建議

          1. 如果我們嘗試將URL直接放入ChatGPT,即使激活了代碼解釋器,它也無法執行網頁抓取。出于這個原因,我們下載要在 HTML 中抓取的頁面
          2. ChatGPT 最初可能無法識別要提取的字段的標簽,并且可能會向我們提供錯誤的信息。此時,我建議打開另一個聊天并再次運行提示
          3. 我們應該記住,代碼解釋器使用Python和庫,如BeautifulSoup進行網頁抓取。
          4. 此方法的目的不是取代傳統的網頁抓取,但是,它將節省我們的時間和代碼行
          5. 我們通過 03 個網頁抓取示例在故事中看到的內容既面向從事編程工作的人,也面向在該領域知之甚少或一無所知的人
          6. 有趣的是,我們可以通過網絡抓取完成什么,正如我上面提到的,我們可以專注于直銷創建 Kindle 書籍,考慮到暢銷書籍分析競爭對手的價格跟蹤某些產品等等

          本完整指南適用于希望使用 ChatGPT 進行網頁抓取的替代方案的人。沒有必要有先前的編程知識,只需要好奇心和耐心。下個故事見,祝福!

          、HTML簡介

          1.HTML是什么?

          HTML:htper text markup language超文本標記(標簽)語言

          由各種標簽組成,用來制作網頁,告訴瀏覽器如何顯示頁面

          2.作用

          • 制作網頁,控制網頁和內容的顯示
          • 插入圖片、音樂、視頻、動畫等多媒體
          • 通過鏈接來檢索信息
          • 使用表單獲取用戶的信息,實現交互

          3.版本

          w3c:world wide web consortium萬維網聯盟,制定web技術相關標準和規范的組織,HTML技術hi由w3c制定的標準

          兩個版本:HTML4.0.1、HTML5.0-----通常H5

          官網:http://www.W3shcool.com.cn

          4.擴展名

          HTML文檔是以.html或.htm結尾

          二、HTML文檔結構

          1.基本結構

          1.1簡介

          • HTML標簽是由尖括號括起來的關鍵詞,如,通常是成對出現的,如<html></html>
          • <html>為根標簽,包含: <head>頭部和<body>主體部分
          • 頭部提供關于網頁的相關信息,如標題、文檔類型、字符編碼、關鍵字等摘要信息
          • 主體部分提供網頁的顯示內容,真正顯示在頁面中的內容
          • 合理地進行縮進
          • 標簽名不區分大小寫,但是一般要用小寫

          1.2.開發工具

          記事本notepad、sublime、Notepad++、Dreamweaver、VScode、Webstorm等

          使用步驟:

          1. 新建文件(cltr+N),然后保存(ctrl+s),指定擴展名為.html
          2. 編寫HTML代碼
          3. 在瀏覽器中打開文件

          使用技巧:

          • 先保存再寫代碼,否則代碼無顏色提示
          • 創建一個文件夾,用于保存所有的網頁內容,將文件夾拖拽到sublime中,便于管理
          • 顯示/隱藏側邊欄方式1:查看–>側邊欄–>顯示/隱藏側邊欄方式2:ctrl+K緊接著按B
          • 顯示多欄方式1:查看–>布局–>列數:2列方式2:Alt+shift+2

          1.3瀏覽器

          常見的瀏覽器:IE瀏覽器微軟、chrome谷歌瀏覽器、fifirefox火狐、safari蘋果

          瀏覽器的作用是讀取html文件,并以網頁的形式來顯示

          瀏覽器不會直接顯示html標簽,而是使用標簽來解釋網頁的內容

          2.標簽

          2.1標簽的組成

          一個完整的html標簽的組成:

          <標簽名 屬性名="屬性值">內容</標簽名>

          <!DOCTYPE html>
          <html lang="en">
          	<head>
          		<meta charset="UTF-8">
          		<title>標簽</title>
          	</head>
          	<body  bgcolor="red" text="blue">
          		html從入門到精通!
              </body>
          </html>
          12345678910

          屬性值要用雙撇號括起來,一般用雙引號

          2.2標簽的分類

          根據標簽是否關閉,分為,關閉型和非關閉型

          • 關閉型:有結束標簽,即標簽成對出現
          <html></html>
          <head></head>
          <title></title>

          非關閉型:沒有結束標簽

          <meta>
          <br>
          <h1>....<h6>

          根據標簽是否獨占一行,分為塊級標簽和行級標簽

          塊級標簽:顯示為塊狀,獨占一行

          <h1>大家好</h1>
          <hr>

          行級標簽:在行內顯示,可與其他內容在同一行顯示

          <span></span>

          2.3注釋

          注釋在瀏覽器中不會顯示,是用來標注解釋html語句,但通過查看源代碼的方式可以看到

          語法:

          <--注釋內容-->

          2.4實體字符

          也稱為特殊字符,用于顯示一些特殊符號,如<>&空格等

          語法:

          <&實體字符的名稱>

          2.5文檔類型

          在html文檔的第一行,使用<!DOCTYPE html>

          聲明HTML文檔的類型用來告訴瀏覽器頁面的文檔嘞型,用來制定html版本的規范

          目前基本上最常用的html5

          <!DOCTYPE html>
          <html lang="en">
          <head>
          	<meta charset="UTF-8">
          	<title>Document</title>
          </head>
          <body>
          	
          </body>
          </html>
          12345678910

          三\常用標簽

          3.1基本標簽

          • 塊級標簽\親啊后有明顯的間隔 |
            | h1…h5 | 標題標簽 | 按照h1到h6逐漸變小.塊級標簽 |
            | | | |
            | | | |


          • 三、常用標簽

          1.基本標簽

          1.1 有序列表
          ol:ordered listli:list item默認使用阿拉伯數字、從1開始標記,可以通過屬性進行修改
          · type屬性:設置列表的符號標記、取值;數字1(默認)、字母(a或A)、羅馬數字(i或I) · start屬性:設置起始值,值必須是數字
          1.2 無序列表
          ul:unodered list
          li:list item
          默認情況下使用實心圓表作為符號標記,可以通過屬性進行修改
          · type屬性:設置列表的符號標記、取值:disc實心圓(默認)、circle空心圓、square正方形、none不 顯示項目符號
          1.3 定義列表
          dl:definition list
          dt:definition title
          dd:definition description
          1.4 水平線標簽
          hr:horizontal
          常用屬性:
          · color:顏色

          兩種方式:

          顏色名稱:如red、green、blue、white、black、pink、orange等

          16進制的RGB表示法:Red、Green、Blue用法:#RRGGBB 每種顏色的取值范值0-255,轉換為16 進制00-FF

          如: #FF0000 紅色 #00FF00綠色 #0000FF藍色 #FFFFFF白色、#CCCCCC #FF7300桔色

          · size:粗細,數值

          · width寬度

          兩種寫法:

          ? 像素:絕對值(固定值)

          ? 百分比:相對值,相對于水平線標簽所在父容器寬度的百分比

          · align對齊

          ? 取值:center居中 left right
          1.5圖像標簽
          img:image
          常見的圖片格式:.jpg .png .gif .bmp
          常見的屬性:
          · src:source指定圖片的路徑(來源),必選叁數

          如果圖片與html源代碼在同一個文件夾中,可以直接在src中寫圖片名稱即可

          習慣上,我們會將多個圖片與html代碼文檔分別放在同一個文件夾project中的不同目錄下,此時需要 在src中指定圖片的路徑為相對路徑

          路徑的分類:

          ? · 相對路徑

          ? 表示: ./當前路徑
          …/當前位置的上一級文件夾

          ? 提示:…/image

          ? · alt:當圖片無法顯示時顯示的提示信息

          ? · title:當鼠標放到圖片上時顯示的提示信息

          ? · width和 height:設置圖片的寬度和高度
          默認圖片以原始尺寸顯示

          ? 如果只設置其中一個,則另一個會按比例縮放

          ? 如果同時設置寬和高,可能導致圖片變形

          ? 兩種寫法:

          ? 像素:絕對值(固定值)

          ? 百分比:相對值,相對于父容器的尺寸的百分比
          2.其他標簽

          為了更好語義化
          3.頭部標簽
          · meta定義網頁的摘要信息,如字符編碼,關鍵詞,描述,作者等
          · title定義網頁的標題
          · style定義內容css樣式
          · link引用外部css樣式
          · script定義或引用腳本
          · base定義基礎路徑
          默認以當前頁面文件所在的位置為相對路徑參照
          4.標簽嵌套
          一個標簽中嵌套另外一個標簽
          標簽不能亂嵌套
          瀏覽器渲染后顯示的頁面代碼與編碼時有所不同
          chrome瀏覽器提供的開發工具:幫助開發人員查看和調試頁面的
          如何打開:
          · Elements:從瀏覽器的角度來看頁面,瀏覽器渲染頁面時內部的結構
          · console:控制臺,顯示各種警告和錯誤信息
          · network:查看網絡請求信息,瀏覽器向服務器請求了哪些資源,資源大小,
          加載資源所消耗的時間

          四、超鏈接
          1.簡介
          使用超鏈接可以從一個頁面跳轉到另外一個頁面,實現頁面之間導航
          當鼠標移動到超鏈接文本或圖片時,鼠標箭頭會變成一只小手
          超鏈接有三種類型:
          普通鏈接/頁面間的鏈接,跳轉到另一個頁面 錨鏈接:鏈接到錨點(鏈接到同一個頁面的指定位置) 功能鏈接:實現特殊功能(發郵件,下載)
          2.基本用法
          使用 標簽來創建超鏈接
          語法格式:

          常用屬性:
          href:鏈接地址或路徑,鏈接地址

          world

          鏈接文本或圖片

          1 2 3 4 5 1 target:鏈接打開的位置,取值

          路徑分類:
          絕對路徑 以根開始的路徑
          file:///D:/software/b.html https://www.baidu.com/img/bd_logo1.png
          相對路徑 相對于當前頁面文件所在的路徑,不是以根開始的路徑 ./ 當前路徑 …/ 當前位置上一級目錄

          3.錨鏈接
          3.1簡介
          點擊鏈接后跳轉到某一個頁面的指定位置(錨點anchor)
          錨鏈接的分類:
          頁面內的錨鏈接 頁面間的錨鏈接
          3.2 頁面內的錨鏈接
          步驟:

          1. 定義錨點(標記)
          2. 鏈接錨點
            _self 自身,當前,默認值 _blank新的,空白的 _parent父層框架 _top頂層框架
            目標位置
            1 2 3 4
            1

          3.3 頁面間的錨鏈接

          4.功能鏈接
          5.URL
          5.1 簡介
          URL:Uniform Resource Locator 統一資源定位器,用來定位資源所在的位置,最常見的就是網址

          5.2 組成
          一個完整的URL由8個部分組成:
          協議:prococol 如 http:超文本傳輸協議,用來訪問WEB網站Hyper text Transfer protocal https:更加安全的協議 SSL安全套接子層 ftp文件傳輸協議,用來訪問服務器上的文件,實現文件的上傳和下載File Transfer protocol file:文件協議,用來訪問本地文件 主機名hostname服務器地址或服務器Netbios名稱,如www.baidu.com ftp://10.255.254.254 端口:port位于主機名的后面,使用冒號進行分隔 不同的協議使用不同的端口,如http使用80端口,https使用的443端口,ftp使用20和21 如果使用的是默認端口,則端口可以省略 如果使用的不是默認端口,則必須指定端口http://59.49.32.213:7070/ 路徑:path目標文件所在的路徑結構,如:www.baidu.com/img/ 資源resource要訪問的目標文件,如bd_logo1.png 查詢字符串:query string 也稱為參數 在資源后面使用?開頭的一組名稱/值
          鏈接文本
          鏈接文本
          https://www.baidu.com/img/bd_logo1.png?name=tom&age=2&sex=male https://www.w3school.com.cn/html/html_quotation_elements.asp file:///C:/Users/Administrator/Desktop/project/code/09.%E5%B8%B8%E7%94%A8%E6%A0%87%E7%A D%BE3.html http://www.sxgjpx.net/ ftp://10.255.254.253/
          1
          1
          1 2 3
          4 5
          名稱和值之間以=分隔,多個之間用&分隔,如:name=tom&age=2&sex=male 錨點anchor,在資源后面使用#開頭的文本,如#6 身份認證authentication,指定身份信息,如:ftp://賬戶:密碼@ftp.bbshh010.com
          五、表格
          1.簡介
          表格是一個規則的行列結構,每個表格是由若干行組成,每行由若干個單元格組成
          table row column
          2.基本結構
          2.1 table標簽
          用來定義表格
          常用屬性:
          border:表格邊框 默認為0 width/height:寬度/高度 bordercolor:邊框的顏色 align:對齊方式,取值:left(默認) center居中 right居右 bgcolor:背景顏色 background:背景圖片 cellspacing間距:單元格與單元格之間的距離 cellpadding邊距:單元格中的內容到邊界之間的距離
          2.2 tr標簽
          用來定義行:table row
          常用屬性:
          align:水平對齊 取值:left(默認) center right valign垂直對齊 取值:top center bottom bgcolor:背景顏色 background:背景圖片
          2.3 td標簽
          用來定義單元格,table data
          常用屬性:align、valign、bgcolor、background
          注意:表格必須是由行組成,行必須由單元格來組成,數據必須放到單元格中
          3.合并單元格
          合并單元格也稱為單元格的跨行跨列
          兩個屬性:
          rowspan 設置單元格所跨的行數 colspan 設置單元格所跨的列數
          步驟:

          1. 在跨越的單元格中設置rowspan/colspan屬性 2. 將被跨越的單元格刪除
            必須要保證每行的實際列數是相同的,否則表格可能會出錯亂
            4.高級標簽
            4.1caption標簽
            表格的標題標簽
            4.2thead標簽
            表格的頭部table head
            4.3th標簽
            表格的頭部標題table head title
            一般用在thead中,設置頭部的標題,替代td標簽,與td的區別,th中的文本會加粗且居中顯示
            4.4tbody標簽
            表格的主體table body
            4.5tfoot標簽
            表格的底部table foot




          六、表單
          1.簡介
          表單是一個包含若干個表單元素的區域,用于獲取瑣類型的用戶數據

          表單元素是允許用戶在表單輸入信息的元素,如文本框、密碼框、單選按鈕、復選框、下拉列表、按鈕等
          2.表單結構
          2.1表單語法

          1

          2.2form標簽
          用來定義表單,可以包含多個表單元素
          常用屬性:
          action:提交數據給誰處理,即處理數據的程序,默認為當前頁面 method:提交數據的方式或方法,取值:get(默認),post get和post的區別: get:以查詢字符串的形式提交,在地址欄中能看到,長度有限制,不安全 post以表單數據組的形式進行提交,在地址欄中看不到,長度無限制,安全 enctype(encode type)編碼類型:提交數據的編碼,取值:application/X-www-form-urlencoded(默 認)、multipart/form-data(文件上傳)
          3.表單元素
          大多數的表單元素都是使用 標簽來定義的,通過設置屬性type來定義不同的表單元素

          1

          3.1單行文本框
          常用屬性:
          ·name名稱,很重要,如果沒有定義name屬性,則該表單元素的數據是無法提交的

          ·value初始值

          ·size顯示寬度

          ·maxlength:大字符數,默認是沒有限制

          ·readonly只讀:readonly=“readonly”,可簡寫readonly,即只寫屬性名

          ·disabled禁用:disabled=“disabled”, 可簡寫disabled完全禁用

          表單元素被提交的兩個條件,1.有name屬性2.非disabled

          3.2 單選按鈕
          常用屬性:

          ·name名稱:多個radio的name屬性必須相同,才能實現互斥(單選)

          ·value值

          ·checked:是否被選中,兩種狀態,選中,未選中 checked=“checked” 簡寫 checked

          3.3 復選框
          常用屬性與單選按鈕radio類似

          3.4 文件選擇器
          常用屬性:

          ·name:名稱

          ·accept設置可選擇的文件類型,用來限制上傳的文件類型

          使用MIME格式字符串對資源類型進行限制

          常見的MIME類型:

          ·純文本:text/plain text/xml text/html

          · 圖像:image/png image/jpeg image/gif

          4.特殊表單元素

          4.1下拉列表

          select常用屬性:

          ·name名稱

          ·size行數,同時顯示多個選項

          ·multiple允許同時選擇多個

          option常用屬性:

          ·value選項值

          ·selected設置默認選中項

          optgroup常用屬性:

          ·label分組的標簽

          4.2文本域

          ·name名稱

          ·rows行數

          ·cols列數


          5、其他標簽

          5.1 label標簽

          為表單元素提供標簽,當選中label標簽中的文本內容時會自動將光標切換到與之相關聯的表單元素。

          常用屬性:

          ·for必須將該屬性值設置為與相關聯的表單元素的Id屬性值相同。

          注:幾乎所有HTML標簽都具有id屬性,且id值必須唯一。

          5.2 button標簽

          也表示按鈕,與input按鈕類似

          語法:

          1按鈕文字或圖像

          常用屬性:

          ·type按鈕的類型,取值: submit(默認)、reset、button

          5.3 fieldset和legend標簽

          fieldset標簽,對表單元素進行分組

          legend標簽,對分組添加標題

          七、內嵌框架
          1、簡介

          使用iframe可以在一個頁面中引用另一個頁面,實現復用、靈活

          2、基本用法

          語法:

          1

          常用屬性:

          · src:引用的頁面

          · width/height寬度/高度 ,像素或百分比

          · frameborder是否顯示邊框,取值:1(yes) 0(no)—默認

          · scrolling是否顯示滾動條,取值:yes no auto

          · name屬性 為框架定義名稱

          3、在框架中打開鏈接

          1

          2

          3鏈接的文本或圖像

          八、HTML5簡介

          1、發展

          W3C于1992年12月發布了HTML4.0.1標準
          W3C于2014年10月發布了HTML5標準

          2、特點

          · 取消了過時的標簽,如font、center等,它們僅具有展示外觀的功能

          · 增加了一些更具有語義化的標簽,如header、footer、aside等

          · 增加了一些新功能標簽,如canvas、audio、video

          · 增加了一些表單控件,如email、date、time、url、search等

          · 可以直接在瀏覽器中繪畫(canvas),無需flash

          · 增加了本地存儲的支持

          3、兼容性

          http://caniuse.com

          提供了各種瀏覽器版本對HTML5和CSS規范的支持度

          九、HTML5新增內容
          1、結構相關的標簽

          用來進行頁面結構布局,本身無任何特殊樣式,需要使用CSS進行樣式設置

          · article定義一個獨立的內容,完整的文章

          · section定義文檔的章節、段落

          · header文章的頭部、頁眉、標題

          · footer文章的底部、頁腳、標注

          · aside定義側邊欄

          · figure圖片區域

          · figcaption為圖片區域定義標題

          · nav定義導航菜單

          結構標簽只是表明各部分的角色,并無實際的外觀樣式,與普通div相同

          2、語義相關的標簽
          2.1 mark標簽
          標注,用來突出顯示文本,默認添加黃色背景
          2.2 time標簽
          定義日期和時間,便于搜索引擎智能查找
          2.3 details和 summary標簽
          默認顯示summary中的內容,點擊后顯示details中的內容
          注:并不是所有的瀏覽器都兼容,chrome、opera支持、Firefox、IE瀏覽器不支持
          2.4 meter標簽
          計數儀,表示度量
          常用屬性:

          · max定義大值,默認為1

          · min定義小值,默認為0

          · value定義當前值

          · high定義限定為高的值

          · low定義限定為低的值

          · optimum定義佳值

          規則:

          1. 如果optimum大于high,則表示值越大越好

          當value大于high時為綠色

          當value在low與high之間時為黃色

          當value小于low時為紅色

          1. 如果optimum小于low,則表示值越小越好

          當value小于low時為綠色

          當value在low與high之間時為黃色

          當value大于high時為紅色

          1. 當optimum介于low和high之間,則表示值在low和high之間好當value在low與high之間時顯示綠色,否則顯示黃色

          2.5 progress標簽
          進度條,表示運行中的進度
          常用屬性:

          · value定義當前值

          · max定義完成的值

          3.表單相關
          3.1 新增表單元素
          新增以下type類型:

          · email接收郵箱

          · url接收URL

          · tel接收電話號碼,目前僅在移動設備上有效

          · search搜索文框

          · number/range接收數字/數字滑塊,包含min,max,step屬性

          · date/month/week/time/datetime日期時間選擇器,兼容性不好

          · color顏色拾取

          作用:

          · 具有格式校驗的功能

          · 可以與移動設備的鍵盤相關聯

          3.2新增表單屬性
          form標簽的屬性:

          · autocomplete是否啟動表單的自動完成功能, 取值:on(默認)、o?

          · novalidate提交表單時不進行校驗,默認會進行表單校驗

          3.3 新增表單元素的屬性
          新增表單元素屬性:input/select/textarea等

          · placeholder提示文字

          · required是否必填

          · autocomplete是否啟用該表單元素的自動完成功能

          · autofocus設置初始焦點元素

          · pattern使用正則表達式(RegExp后面會講解),進行數據校驗

          · list使文本元素具有下拉列表的功能,需要配合datalist和option標簽一起使用

          · form可以將表單元素寫在form標簽外面,然后通過該屬性關聯指定的表單

          4、多媒體標簽
          4.1audio標簽
          在頁面中插入音頻,不同的瀏覽器對音頻格式的支持不一樣
          audio常用屬性:

          · src音頻文件的來源

          · controls是否顯示控制面板,默認不顯示

          · autoplay是否自動播放,默認不自動播放

          · loop是否循環播放

          · muted是否靜音

          · preload是否預加載,取值:none不預加載、auto預加載(默認)、metadata只加載元數據

          如果設置了autoplay屬性,則該屬性無效

          可以結合source標簽使用,指定多個音頻文,瀏覽器會檢測并使用第一個可用的音頻文件

          4.2 video標簽
          在頁面中插入視頻,不同的瀏覽器對視頻格式的支持不一樣
          用法與audio標簽基本相同,增加屬性:

          · widht/height視頻播放器的寬度/高度

          · poster在視頻加載前顯示的圖片

          案例1hello.html

          <html>
          	<body>
          		<tiele>HTML技術</tiele>
          	</body>
          	<body>
          		大家好,歡迎學習html技術!
          	</body>
          </html>1234567

          效果

          [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-h271e4v6-1593240920352)(C:\Users\lenovo\Desktop\新建文件夾\靜態網頁2\案例\result\案例1.png)]

          案例2標簽的組成.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
          	<meta charset="UTF-8">
          	<title>標簽</title>
          </head>
          <body text="blue">
          	標簽的組成
          	<br>
          	html從入門到精通!
          	<hr>
          	<h1>標簽的分類</h1>
          	<hr>
          
          	<h2>標簽的分類</h2>
          	<hr>
          
          	<h6>標簽的分類</h6>
          	<hr>
          
          	<span>哈哈</span>嘿嘿
          	
          </body>
          </html>1234567891011121314151617181920212223

          效果

          [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jx6zJE1P-1593240920354)(C:\Users\lenovo\Desktop\新建文件夾\靜態網頁2\案例\result\案例2.png)]

          案例3實體字符.html

          <!DOCTYPE html>
          <html lang="en">
          <head>
          	<meta charset="UTF-8">
          	<title>Document</title>
          </head>
          <body>
          	圖書:<<HTML從入門到精通<<
          	<hr>
          
          	北京      上海      廣州
          	<hr>
          
          	在HTML中用<表示<小于號
          	<hr>
          
          	“HTML語言” 或 &qout;HTML語言&qout;
          	<hr>
          
          	版權所有? 2000-2020 高教培訓
          	<hr>
          
          	×關閉符號
          </body>
          </html>123456789101112131415161718192021222324

          效果

          [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nuFLl3hm-1593240920355)(C:\Users\lenovo\Desktop\新建文件夾\靜態網頁2\案例\result\案例3.png)]

          (剩下的下期出)

          原文鏈接:https://blog.csdn.net/WanXuang/article/details/106982782?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160513384519724835852804%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=160513384519724835852804&biz_id=&utm_medium=distribute.pc_search_top_result.none-task-code-2~all~top_position~default-1-106982782-12.nonecase&utm_term=html

          作者:WanXuang

          出處:從CSDN

          踐過程中,我們使用Jira做統一的項目管理和缺陷管理。在測試完成之后,測試同學需要發送測試報告或者release notes給項目組成員,雖然Jira自身提供了基于release管理的release notes的自動生成,但其界面不太友好,所以有必要我們做一下二次開發。

          一般測試報告的生成,采用word格式(直接套用定義好的模板,填入數據)、html格式或者mardown等格式,其中html和markdown格式非常方便程序的自動生成,我們兩種方式都支持。

          而在測試報告的發送這一塊,可以發送一個鏈接,可以發送一個附件,也可以在郵件內部鏈接上報告的內容。如此,html格式最為適合。其中在附件類型選擇上,html或者pdf都具有很好的顯示效果和跨平臺性。此處為了方便存檔,我們增加了pdf格式的測試報告的自動生成。

          wkhtmltopdf簡介

          其官網為:https://wkhtmltopdf.org/index.html。

          首先我們復制一下官網介紹:

          What is it?

          wkhtmltopdf and wkhtmltoimage are open source (LGPLv3) command line tools to render HTML into PDF and various image formats using the Qt WebKit rendering engine. These run entirely "headless" and do not require a display or display service.

          There is also a C library, if you're into that kind of thing.

          簡單翻譯一下:wkhtmltopdf和wkhtmltoimage是基于開源LGPLv3協議的命令行工具,它使用Qt webkit渲染引擎把HTML渲染為PDF。運行的時候,是“無頭”的并不需要顯示器或者顯示服務。

          同時該工具也提供了基于C的庫文件。

          How do I use it?

          1. Download a precompiled binary or build from source
          2. Create your HTML document that you want to turn into a PDF (or image)
          3. Run your HTML document through the tool.
          4. For example, if I really like the treatment Google has done to their logo today and want to capture it forever as a PDF:
          5. wkhtmltopdf http://google.com google.pdf

          再簡單翻譯一下使用方法:下載二進制文件或者從源文件構建;創建html文件;以google為例進行html到pdf的轉換: wkhtmltopdf http://google.com google.pdf即可。

          整體看,wkhtmltopdf使用起來很方便,pdf轉換效果很理想,安裝也簡單。其下載地址為:https://wkhtmltopdf.org/downloads.html

          定義html模板文件

          測試報告的html模板,這里列出一些共性的東西:上線內容、缺陷統計、研發效率等,大家可以結合自身的業務需要進行添加。簡單的實現,可以直接做字符串替換,麻煩點的,就可以用thymeleaf等模板文件了:

          <html>
           <meta http-equiv="content-type" content="text/html;charset=utf-8">
           <head>
           <style type="text/css">
           body{
           font-size: 9pt;
           }
           table{border-collapse: collapse;width:800px;}
           tr{}
           td{border: 1px solid #0D3349;padding:5px;font-size:9pt;}
           .tr-label{
           background-color: #2D64B3;
           color:#ffffff;
           }
           a{
           text-decoration: none;
           color:#000000;
           }
           </style>
           <title>{{REPORT_TITLE}}</title>
           </head>
           <body>
           <h1>{{REPORT_TITLE}}</h1>
           <hr style="size:1px;"/>
           <p><h2>上線內容:</h2></p>
           <table>
           <tr class="tr-label">
           <td width="150px">類別</td>
           <td>內容</td>
           </tr>
           {{RELEASE_NOTE}}
           </table>
           <p><h2>缺陷分析 - 根據模塊:</h2></h2></p>
           <table>
           <tr class="tr-label">
           <td width="150px">模塊名稱</td>
           <td>個數</td>
           </tr>
           {{ISSUE_COMPONENT}}
           </table>
           <p><h2>缺陷分析 - 根據根據狀態:</h2></p>
           <table>
           <tr class="tr-label">
           <td width="150px">狀態</td>
           <td>個數</td>
           </tr>
           {{ISSUE_STATUS}}
           </table>
           <p><h2>缺陷分析 - 根據優先級:</h2></p>
           <table>
           <tr class="tr-label">
           <td width="150px">優先級</td>
           <td>個數</td>
           </tr>
           {{ISSUE_PRIORITY}}
           </table>
           <p><h2>缺陷分析 - 根據經辦人:</h2></p>
           <table>
           <tr class="tr-label">
           <td width="150px">經辦人</td>
           <td>個數</td>
           </tr>
           {{ISSUE_ASSIGNEE}}
           </table>
           <p><h2>缺陷分析 - 根據報告人:</h2></p>
           <table>
           <tr class="tr-label">
           <td width="150px">報告人</td>
           <td>個數</td>
           </tr>
           {{ISSUE_REPORTER}}
           </table>
           <p><h2>缺陷開發測試效率</h2></p>
           <table>
           <tr class="tr-label">
           <td width="150px">類別</td>
           <td>耗時(小時)</td>
           </tr>
           <tr>
           <td width="150px">開發響應平均耗時</td>
           <td>{{DEV_REACT}}</td>
           </tr>
           <tr>
           <td width="150px">開發處理平均耗時</td>
           <td>{{DEV_PROCESS}}</td>
           </tr>
           <tr>
           <td width="150px">測試響應平均耗時</td>
           <td>{{TEST_REACT}}</td>
           </tr>
           <tr>
           <td width="150px">測試處理平均耗時</td>
           <td>{{TEST_PROCESS}}</td>
           </tr>
           </table>
           </body>
          </html>
          

          結果數據的獲取

          上文提到,我們才用Jira做項目管理,所以測試數據的獲取,主要還是使用Jira-client這個三方jar,個別地方,比如缺陷時間這一塊,采用直接query數據庫的方式實現以提高效率,關鍵代碼如下(注意里面夾雜了mardown格式的):

          /**
           * 獲取根據jql生成的issue
           * @param jql
           * @return
           * @throws Exception
           */
          public List<Issue> getIssues(String jql) throws Exception{
           Iterator<Issue> iterator = jiraClient.searchIssues(jql).iterator();
           List<Issue> list = new ArrayList<>();
           while(iterator.hasNext()){
           list.add(iterator.next());
           }
           return list;
          }
          /**
           * 生成報告
           * @param title
           * @param jql
           * @return
           * @throws Exception
           */
          public String[] generateReport(String title, String jql) throws Exception{
           String[] content = generateReport(getIssues(jql));
           for(int i = 0; i < content.length; i ++){
           content[i] = content[i].replace("{{REPORT_TITLE}}", title);
           }
           return content;
          }
          /**
           * 測試報告生成pdf
           * @param title
           * @param jql
           * @throws Exception
           */
          public File generateReportPdf(String title, String jql) throws Exception{
           String html = generateReport(title, jql)[1];
           LocalDateTime localDate = LocalDateTime.now();
           String date = localDate.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
           String htmlFileName = jiraReportPath + "/" + date + ".html";
           IOUtils.write(html, new FileOutputStream(new File(htmlFileName)));
           String pdfFileName = jiraReportPath + "/" + date + ".pdf";
           String cmd = wkthmltopdfCmd + " " + htmlFileName + " " + pdfFileName;
           Process process = Runtime.getRuntime().exec(cmd);
           process.waitFor();
           return new File(pdfFileName);
          }
          private int timediffToMinutes(String timeDiff){
           String[] info = timeDiff.split(":");
           return Integer.valueOf(info[0]) * 60 + Integer.valueOf(info[1]);
          }
          /**
           * 獲取issue的開發、測試響應和處理耗時
           * @param issueList
           * @return
           */
          private String[] issueReactProcess(List<Issue> issueList){
           List<Integer> devReact = new ArrayList<>();
           List<Integer> devProcess = new ArrayList<>();
           List<Integer> testReact = new ArrayList<>();
           List<Integer> testProcess = new ArrayList<>();
           String[] result = new String[8];
           int maxSingleDevReact = 0;
           int maxSingleDevProcess = 0;
           int maxSingleTestReact = 0;
           int maxSingleTestProcess = 0;
           for(Issue issue : issueList){
           if((issue.getIssueType().getName().equalsIgnoreCase("BUG")
           || issue.getIssueType().getName().equalsIgnoreCase("缺陷")
           || issue.getIssueType().getName().equalsIgnoreCase("故障")) && issue.getStatus().getName().equalsIgnoreCase("測試通過")){//只統計測試通過的
           log.info(">>> 添加需要統計耗時的缺陷:{}", issue.getKey());
           try {
           String sql = "select timediff(changegroup.created,jiraissue.created) from changeitem,changegroup,jiraissue where \n" +
           "changeitem.field='status' and changeitem.groupid in (select id from changegroup where issueid=" + issue.getId() + ") and changeitem.groupid=changegroup.id \n" +
           "and changegroup.issueid=jiraissue.id and changeitem.newString='處理中';";
           int singleDevReact = timediffToMinutes(jiraJdbcTemplate.queryForObject(sql, String.class));
           devReact.add(singleDevReact);
           if(singleDevReact > maxSingleDevReact){
           maxSingleDevReact = singleDevReact;
           try {
           result[4] = "<a href='" + IssueUtils.webUrl(issue) + "' target='_blank'>" + issue.getSummary() + "</a>";
           } catch (Exception e) {
           e.printStackTrace();
           }
           }
           sql = "select timediff(changegroup.created,jiraissue.created) from changeitem,changegroup,jiraissue where \n" +
           "changeitem.field='status' and changeitem.groupid in (select id from changegroup where issueid=" + issue.getId() + ") and changeitem.groupid=changegroup.id \n" +
           "and changegroup.issueid=jiraissue.id and changeitem.newString='開發完成';";
           int singleDevProcess = timediffToMinutes(jiraJdbcTemplate.queryForObject(sql, String.class));
           devProcess.add(singleDevProcess - singleDevReact);
           if(singleDevProcess > maxSingleDevProcess){
           maxSingleDevProcess = singleDevProcess;
           try {
           result[5] = "<a href='" + IssueUtils.webUrl(issue) + "' target='_blank'>" + issue.getSummary() + "</a>";
           } catch (Exception e) {
           e.printStackTrace();
           }
           }
           sql = "select timediff(changegroup.created,jiraissue.created) from changeitem,changegroup,jiraissue where \n" +
           "changeitem.field='status' and changeitem.groupid in (select id from changegroup where issueid=" + issue.getId() + ") and changeitem.groupid=changegroup.id \n" +
           "and changegroup.issueid=jiraissue.id and changeitem.newString='測試進行中';";
           int singleTestReact = timediffToMinutes(jiraJdbcTemplate.queryForObject(sql, String.class));
           testReact.add(singleTestReact - singleDevProcess);
           if(singleTestReact > maxSingleTestReact){
           maxSingleTestReact = singleTestReact;
           try {
           result[6] = "<a href='" + IssueUtils.webUrl(issue) + "' target='_blank'>" + issue.getSummary() + "</a>";
           } catch (Exception e) {
           e.printStackTrace();
           }
           }
           sql = "select timediff(changegroup.created,jiraissue.created) from changeitem,changegroup,jiraissue where \n" +
           "changeitem.field='status' and changeitem.groupid in (select id from changegroup where issueid=" + issue.getId() + ") and changeitem.groupid=changegroup.id \n" +
           "and changegroup.issueid=jiraissue.id and changeitem.newString='測試通過';";
           int singleTestProcess = timediffToMinutes(jiraJdbcTemplate.queryForObject(sql, String.class));
           testProcess.add(singleTestProcess - singleTestReact);
           if(singleTestProcess > maxSingleTestProcess){
           maxSingleTestProcess = singleTestProcess;
           try {
           result[7] = "<a href='" + IssueUtils.webUrl(issue) + "' target='_blank'>" + issue.getSummary() + "</a>";
           } catch (Exception e) {
           e.printStackTrace();
           }
           }
           } catch (DataAccessException e) {
           continue;
           }
           }
           }
           result[0] = String.valueOf(generateIssueDuration(devReact));
           result[1] = String.valueOf(generateIssueDuration(devProcess));
           result[2] = String.valueOf(generateIssueDuration(testReact));
           result[3] = String.valueOf(generateIssueDuration(testProcess));
           return result;
          }
          private double generateIssueDuration(List<Integer> list){
           DescriptiveStatistics descriptiveStatistics = new DescriptiveStatistics();
           for(int d : list){
           descriptiveStatistics.addValue(d / 60f);//按小時統計
           }
           double r = 0;
           try{
           r = new BigDecimal(descriptiveStatistics.getMean()).setScale(BigDecimal.ROUND_HALF_UP, 2).doubleValue();
           }catch(Exception e){
           }
           return r;
          }
          /**
           * 生成報告
           * @param issueList
           * @throws Exception
           */
          private String[] generateReport(List<Issue> issueList) throws Exception{
           String[] issueReactProcessResult = issueReactProcess(issueList);
           Map<String, String> ldapUserMap = new HashMap<>();
           for(LdapUserEntity ldapUserEntity : ldapUserService.allUsers()){
           ldapUserMap.put(ldapUserEntity.getUserName(), ldapUserEntity.getDisplayName());
           }
           ldapUserMap.put("TBD", "TBD");
           String content = IOUtils.toString(new ClassPathResource("jira/report.md").getInputStream(), "utf-8");
           String content2 = IOUtils.toString(new ClassPathResource("jira/jira_release_report.html").getInputStream(), "utf-8");
           content2 = content2.replace("{{DEV_REACT}}", issueReactProcessResult[0]);
           content2 = content2.replace("{{DEV_PROCESS}}", issueReactProcessResult[1]);
           content2 = content2.replace("{{TEST_REACT}}", issueReactProcessResult[2]);
           content2 = content2.replace("{{TEST_PROCESS}}", issueReactProcessResult[3]);
           content2 = content2.replace("{{MAX_DEV_REACT}}", issueReactProcessResult[4]);
           content2 = content2.replace("{{MAX_DEV_PROCESS}}", issueReactProcessResult[5]);
           content2 = content2.replace("{{MAX_TEST_REACT}}", issueReactProcessResult[6]);
           content2 = content2.replace("{{MAX_TEST_PROCESS}}", issueReactProcessResult[7]);
           Map<String, List<String>> releaseNote = new HashMap<>();
           Map<String, Integer> issuePriority = new HashMap<>();
           Map<String, Integer> issueAssignee = new HashMap<>();
           Map<String, Integer> issueReporter = new HashMap<>();
           Map<String, Integer> issueStatus = new HashMap<>();
           Map<String, Integer> component = new HashMap<>();
           Comparator<Map.Entry<String, Integer>> comparator = new Comparator<Map.Entry<String, Integer>>() {
           @Override
           public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
           if(o1.getKey().equalsIgnoreCase(o2.getKey())){
           return o2.getValue().compareTo(o1.getValue());
           }
           else{
           return o1.getKey().compareTo(o2.getKey());
           }
           }
           };
           for(Issue issue : issueList){
           //生成release note
           String type = issue.getIssueType().getName();
           if(!releaseNote.keySet().contains(type)){
           releaseNote.put(type, new ArrayList<String>());
           }
           releaseNote.get(type).add(issue.getKey() + ":" + issue.getSummary());
           if("bug".equalsIgnoreCase(type) || "故障".equalsIgnoreCase(type)) {
           //統計priority
           String priority = issue.getPriority().getName();
           if (!issuePriority.keySet().contains(priority)) {
           issuePriority.put(priority, 0);
           }
           issuePriority.put(priority, issuePriority.get(priority) + 1);
           //統計assignee
           String assignee = "TBD";
           try {
           assignee = issue.getAssignee().getName();
           } catch (Exception e) {
           log.error(e.getMessage(), e);
           }
           if (!issueAssignee.keySet().contains(assignee)) {
           issueAssignee.put(assignee, 0);
           }
           issueAssignee.put(assignee, issueAssignee.get(assignee) + 1);
           //統計reporter
           String reporter = "TBD";
           try {
           reporter = issue.getReporter().getName();
           } catch (Exception e) {
           log.error(e.getMessage(), e);
           }
           if (!issueReporter.keySet().contains(reporter)) {
           issueReporter.put(reporter, 0);
           }
           issueReporter.put(reporter, issueReporter.get(reporter) + 1);
           //統計issue status
           String status = issue.getStatus().getName();
           if (!issueStatus.keySet().contains(status)) {
           issueStatus.put(status, 0);
           }
           issueStatus.put(status, issueStatus.get(status) + 1);
           //統計component
           for (net.rcarz.jiraclient.Component c : issue.getComponents()) {
           String cc = c.getName();
           if (!component.keySet().contains(cc)) {
           component.put(cc, 0);
           }
           component.put(cc, component.get(cc) + 1);
           }
           }
           }
           //issuePriority排序
           List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(issuePriority.entrySet());
           Collections.sort(list, comparator);
           StringBuilder sb = new StringBuilder();
           StringBuilder sb2 = new StringBuilder();
           sb.append("| 級別 | 個數 |\n");
           sb.append("|:----|----:|\n");
           for(Map.Entry<String, Integer> entry : list){
           sb.append("| " + entry.getKey() + " | " + entry.getValue() + " |\n");
           sb2.append("<tr><td>" + entry.getKey() + "</td><td>" + entry.getValue() + "</td></tr>");
           }
           content = content.replace("{{ISSUE_PRIORITY}}", sb.toString());
           content2= content2.replace("{{ISSUE_PRIORITY}}", sb2.toString());
           //issueassignee
           list = new ArrayList<Map.Entry<String, Integer>>(issueAssignee.entrySet());
           Collections.sort(list, comparator);
           sb = new StringBuilder();
           sb2 = new StringBuilder();
           sb.append("| 經辦人 | 個數 |\n");
           sb.append("|:----|----:|\n");
           for(Map.Entry<String, Integer> entry : list){
           sb.append("| " + entry.getKey() + " | " + entry.getValue() + " |\n");
           sb2.append("<tr><td>" + ldapUserMap.get(entry.getKey()) + "</td><td>" + entry.getValue() + "</td></tr>");
           }
           content = content.replace("{{ISSUE_ASSIGNEE}}", sb.toString());
           content2 = content2.replace("{{ISSUE_ASSIGNEE}}", sb2.toString());
           //issue reporter
           list = new ArrayList<Map.Entry<String, Integer>>(issueReporter.entrySet());
           Collections.sort(list, comparator);
           sb = new StringBuilder();
           sb2 = new StringBuilder();
           sb.append("| 報告人 | 個數 |\n");
           sb.append("|:----|----:|\n");
           for(Map.Entry<String, Integer> entry : list){
           sb.append("| " + entry.getKey() + " | " + entry.getValue() + " |\n");
           sb2.append("<tr><td>" + ldapUserMap.get(entry.getKey()) + "</td><td>" + entry.getValue() + "</td></tr>");
           }
           content = content.replace("{{ISSUE_REPORTER}}", sb.toString());
           content2 = content2.replace("{{ISSUE_REPORTER}}", sb2.toString());
           //issuestatus
           list = new ArrayList<Map.Entry<String, Integer>>(issueStatus.entrySet());
           Collections.sort(list, comparator);
           sb = new StringBuilder();
           sb2 = new StringBuilder();
           sb.append("| 狀態 | 個數 |\n");
           sb.append("|:----|----:|\n");
           for(Map.Entry<String, Integer> entry : list){
           sb.append("| " + entry.getKey() + " | " + entry.getValue() + " |\n");
           sb2.append("<tr><td>" + entry.getKey() + "</td><td>" + entry.getValue() + "</td></tr>");
           }
           content = content.replace("{{ISSUE_STATUS}}", sb.toString());
           content2 = content2.replace("{{ISSUE_STATUS}}", sb2.toString());
           //issue component
           list = new ArrayList<Map.Entry<String, Integer>>(component.entrySet());
           Collections.sort(list, comparator);
           sb = new StringBuilder();
           sb2 = new StringBuilder();
           sb.append("| 模塊 | 個數 |\n");
           sb.append("|:----|----:|\n");
           for(Map.Entry<String, Integer> entry : list){
           sb.append("| " + entry.getKey() + " | " + entry.getValue() + " |\n");
           sb2.append("<tr><td>" + entry.getKey() + "</td><td>" + entry.getValue() + "</td></tr>");
           }
           content = content.replace("{{ISSUE_COMPONENT}}", sb.toString());
           content2 = content2.replace("{{ISSUE_COMPONENT}}", sb2.toString());
           //release note
           List<Map.Entry<String, List<String>>> list2 = new ArrayList<>(releaseNote.entrySet());
           Collections.sort(list2, new Comparator<Map.Entry<String, List<String>>>() {
           @Override
           public int compare(Map.Entry<String, List<String>> o1, Map.Entry<String, List<String>> o2) {
           return o1.getKey().compareTo(o2.getKey());
           }
           });
           sb = new StringBuilder();
           sb2 = new StringBuilder();
           Comparator<String> comparator2 = new Comparator<String>() {
           @Override
           public int compare(String o1, String o2) {
           return o1.substring(0, o1.indexOf(":")).compareTo(o2.substring(0, o2.indexOf(":")));
           }
           };
           for(Map.Entry<String, List<String>> entry : list2){
           List<String> valueList = entry.getValue();
           Collections.sort(valueList, comparator2);
           for(String v : valueList) {
           sb.append("* [ " + entry.getKey() + " ] " + v + "\n");
           sb2.append("<tr><td>" + entry.getKey() + "</td><td><a href='" + jiraIssueBrowseUrl + v.substring(0, v.indexOf(":")) + "' target='_blank'>" + v + "</a></td></tr>");
           }
           }
           content = content.replace("{{RELEASE_NOTE}}", sb.toString());
           content2 = content2.replace("{{RELEASE_NOTE}}", sb2.toString());
           return new String[]{content, content2};
          }
          private String jiraBugSummaryProcessUser(String user){
           String[] reporters = user.split(",");
           for(int i = 0; i < reporters.length; i ++){
           reporters[i] = "'" + reporters[i] + "'";
           }
           user = StringUtils.join(reporters, ",");
           return user;
          }
          /**
           *
           * @param type
           * @param user
           * @return
           */
          public List<String> jiraBugSummaryLabel(String type, String user){
           user = jiraBugSummaryProcessUser(user);
           String sql = "";
           if("reporter".equalsIgnoreCase(type) || "depReporter".equalsIgnoreCase(type)){
           sql = "select distinct(date_format(a.created, '%Y%m')) as sdate from jiraissue a where a.reporter in(" + user + ")";
           }
           else if("assignee".equalsIgnoreCase(type) || "depAssignee".equalsIgnoreCase(type)){
           sql = "select distinct(date_format(a.created, '%Y%m')) as sdate from jiraissue a where a.assignee in(" + user + ")";
           }
           List<String> list = jiraJdbcTemplate.queryForList(sql, String.class);
           Collections.sort(list, new Comparator<String>() {
           @Override
           public int compare(String o1, String o2) {
           return o1.compareTo(o2);
           }
           });
           return list;
          }
          public List<JiraBugSummaryEntity> jiraBugSummary(String type, String user, String dep){
           user = jiraBugSummaryProcessUser(user);
           String sql = "";
           if("reporter".equalsIgnoreCase(type)){
           sql = "select count(1) as `count`, date_format(a.created, '%Y%m') as sdate, a.reporter as `user`";
           sql += " from jiraissue a where a.issuetype in ('10004', '10207') and a.reporter in(" + user + ") group by sdate,user order by sdate";
           }
           else if("assignee".equalsIgnoreCase(type)){
           sql = "select count(1) as `count`, date_format(a.created, '%Y%m') as sdate, a.assignee as `user`";
           sql += " from jiraissue a where a.issuetype in ('10004', '10207') and a.assignee in(" + user + ") group by sdate,user order by sdate";
           }
           else if("depReporter".equalsIgnoreCase(type)){
           sql = "select count(1) as `count`, date_format(a.created, '%Y%m') as sdate, '" + dep + "' as `user`";
           sql += " from jiraissue a where a.issuetype in ('10004', '10207') and a.reporter in(" + user + ") group by sdate order by sdate";
           }
           else if("depAssignee".equalsIgnoreCase(type)){
           sql = "select count(1) as `count`, date_format(a.created, '%Y%m') as sdate, '" + dep + "' as `user`";
           sql += " from jiraissue a where a.issuetype in ('10004', '10207') and a.assignee in(" + user + ") group by sdate order by sdate";
           }
           List<JiraBugSummaryEntity> list = jiraJdbcTemplate.query(sql, new BeanPropertyRowMapper<JiraBugSummaryEntity>(JiraBugSummaryEntity.class));
           return list;
          }
          
          

          都是一些常規用法,就不解釋代碼了。


          主站蜘蛛池模板: 欧美av色香蕉一区二区蜜桃小说 | 少妇无码一区二区三区| 亚洲美女视频一区| 日韩美一区二区三区| 亚洲国产欧美国产综合一区 | 夜夜添无码试看一区二区三区| 精品国产一区二区三区在线观看| 无码精品人妻一区二区三区免费看| 国产一区二区三区播放| 久久精品无码一区二区WWW| 国产色精品vr一区区三区| 精品一区二区三区| 久久se精品一区二区国产| 久久国产三级无码一区二区| 日本不卡免费新一区二区三区| 亚洲av综合av一区二区三区| 午夜福利一区二区三区高清视频| 国产伦一区二区三区高清 | 国产乱人伦精品一区二区| 日韩精品在线一区二区| 国产一区二区三区精品视频| 亚洲AV无码一区二区三区性色| 亚洲成av人片一区二区三区| 亚洲Av高清一区二区三区| 国产成人精品一区二区三区无码| 无码人妻精品一区二区三区9厂| 久久精品国产一区二区三区肥胖 | 亚洲一区在线免费观看| 呦系列视频一区二区三区| 日韩视频一区二区| 冲田杏梨AV一区二区三区| 午夜AV内射一区二区三区红桃视| 人妻体体内射精一区二区| 天堂资源中文最新版在线一区 | 亚洲人成网站18禁止一区| 亚洲一区二区三区不卡在线播放| 国产视频一区在线观看| 国产在线一区二区综合免费视频| 国产一区二区视频在线观看| 中文字幕亚洲一区二区三区| 精品国产不卡一区二区三区|