整合營銷服務商

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

          免費咨詢熱線:

          Python|簡單幾行代碼提取html文件中全部指定標簽內的文本

          有以下文件html.html:

          想要提取全部標簽<h4></h4>內的文本,可使用如下Python代碼:

          import re

          with open("html.html",'rU') as strf:

          ....str = strf.read()

          res = r'(?<=<h4>).*?(?=</h4>)'

          li = re.findall(res,str)

          with open("new.txt","w") as wstr:

          ....for s in li:

          ........wstr.write(s)

          ........wstr.write("\r\n")

          ........print(s,'\r\n')

          正則表達式r'(?<=<h4>).*?(?=</h4>)中括號部分屬于向后向前查找,相當于字符串作為邊界進行查找。

          運行后會將標簽<h4></h4>內的文本提取到文件new.txt:

          -End-

          x1 工具準備

          工欲善其事必先利其器,爬取語料的根基便是基于python。

          我們基于python3進行開發,主要使用以下幾個模塊:requests、lxml、json。

          簡單介紹一個各模塊的功能

          01|requests

          requests是一個Python第三方庫,處理URL資源特別方便。它的官方文檔上寫著大大口號:HTTP for Humans(為人類使用HTTP而生)。相比python自帶的urllib使用體驗,筆者認為requests的使用體驗比urllib高了一個數量級。

          我們簡單的比較一下:

          urllib:

           1import urllib2
           2import urllib
           3
           4URL_GET = "https://api.douban.com/v2/event/list"
           5#構建請求參數
           6params = urllib.urlencode({'loc':'108288','day_type':'weekend','type':'exhibition'})
           7
           8#發送請求
           9response = urllib2.urlopen('?'.join([URL_GET,'%s'])%params)
          10#Response Headers
          11print(response.info())
          12#Response Code
          13print(response.getcode())
          14#Response Body
          15print(response.read())
          復制代碼
          

          requests:

           1import requests
           2
           3URL_GET = "https://api.douban.com/v2/event/list"
           4#構建請求參數
           5params = {'loc':'108288','day_type':'weekend','type':'exhibition'}
           6
           7#發送請求
           8response = requests.get(URL_GET,params=params)
           9#Response Headers
          10print(response.headers)
          11#Response Code
          12print(response.status_code)
          13#Response Body
          14print(response.text)復制代碼
          

          我們可以發現,這兩種庫還是有一些區別的:

          1. 參數的構建:urllib需要對參數進行urlencode編碼處理,比較麻煩;requests無需額外編碼處理,十分簡潔。

          2. 請求發送:urllib需要額外對url參數進行構造,變為符合要求的形式;requests則簡明很多,直接get對應鏈接與參數。

          3. 連接方式:看一下返回數據的頭信息的“connection”,使用urllib庫時,"connection":"close",說明每次請求結束關掉socket通道,而使用requests庫使用了urllib3,多次請求重復使用一個socket,"connection":"keep-alive",說明多次請求使用一個連接,消耗更少的資源

          4. 編碼方式:requests庫的編碼方式Accept-Encoding更全,在此不做舉例

          綜上所訴,使用requests更為簡明、易懂,極大的方便我們開發。

          02|lxml

          BeautifulSoup是一個庫,而XPath是一種技術,python中最常用的XPath庫是lxml。

          當我們拿到requests返回的頁面后,我們怎么拿到想要的數據呢?這個時候祭出lxml這強大的HTML/XML解析工具。python從不缺解析庫,那么我們為什么要在眾多庫里選擇lxml呢?我們選擇另一款出名的HTML解析庫BeautifulSoup來進行對比。

          我們簡單的比較一下:

          BeautifulSoup:

          1from bs4 import BeautifulSoup #導入庫
          2# 假設html是需要被解析的html
          3
          4#將html傳入BeautifulSoup 的構造方法,得到一個文檔的對象
          5soup = BeautifulSoup(html,'html.parser',from_encoding='utf-8')
          6#查找所有的h4標簽 
          7links = soup.find_all("h4")
          復制代碼
          

          lxml:

          1from lxml import etree
          2# 假設html是需要被解析的html
          3
          4#將html傳入etree 的構造方法,得到一個文檔的對象
          5root = etree.HTML(html)
          6#查找所有的h4標簽 
          7links = root.xpath("http://h4")
          復制代碼
          

          我們可以發現,這兩種庫還是有一些區別的:

          1. 解析html: BeautifulSoup的解析方式和JQ的寫法類似,API非常人性化,支持css選擇器;lxml的語法有一定的學習成本

          2. 性能:BeautifulSoup是基于DOM的,會載入整個文檔,解析整個DOM樹,因此時間和內存開銷都會大很多;而lxml只會局部遍歷,另外lxml是用c寫的,而BeautifulSoup是用python寫的,明顯的性能上lxml>>BeautifulSoup。

          綜上所訴,使用BeautifulSoup更為簡明、易用,lxml雖然有一定學習成本,但總體也很簡明易懂,最重要的是它基于C編寫,速度快很多,對于筆者這種強迫癥,自然而然就選lxml啦。

          03|json

          python自帶json庫,對于基礎的json的處理,自帶庫完全足夠。但是如果你想更偷懶,可以使用第三方json庫,常見的有demjson、simplejson。

          這兩種庫,無論是import模塊速度,還是編碼、解碼速度,都是simplejson更勝一籌,再加上兼容性 simplejson 更好。所以大家如果想使用方庫,可以使用simplejson。

          0x2 確定語料源

          將武器準備好之后,接下來就需要確定爬取方向。

          以電競類語料為例,現在我們要爬電競類相關語料。大家熟悉的電競平臺有企鵝電競、企鵝電競和企鵝電競(斜眼),所以我們以企鵝電競上直播的游戲作為數據源進行爬取。

          我們登陸企鵝電競官網,進入游戲列表頁,可以發現頁面上有很多游戲,通過人工去寫這些游戲名收益明顯不高,于是我們就開始我們爬蟲的第一步:游戲列表爬取。


           1import requests
           2from lxml import etree
           3
           4# 更新游戲列表
           5def _updateGameList():
           6 # 發送HTTP請求時的HEAD信息,用于偽裝為瀏覽器
           7 heads = { 
           8 'Connection': 'Keep-Alive',
           9 'Accept': 'text/html, application/xhtml+xml, */*',
          10 'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
          11 'Accept-Encoding': 'gzip, deflate',
          12 'User-Agent': 'Mozilla/6.1 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
          13 }
          14 # 需要爬取的游戲列表頁
          15 url = 'https://egame.qq.com/gamelist'
          16
          17 # 不壓縮html,最大鏈接時間為10妙
          18 res = requests.get(url, headers=heads, verify=False, timeout=10)
          19 # 為防止出錯,編碼utf-8
          20 res.encoding = 'utf-8'
          21 # 將html構建為Xpath模式
          22 root = etree.HTML(res.content)
          23 # 使用Xpath語法,獲取游戲名
          24 gameList = root.xpath("http://ul[@class='livelist-mod']//li//p//text()")
          25 # 輸出爬到的游戲名
          26 print(gameList)
          復制代碼
          

          當我們拿到這幾十個游戲名后,下一步就是對這幾十款游戲進行語料爬取,這時候問題就來了,我們要從哪個網站來爬這幾十個游戲的攻略呢,taptap?多玩?17173?在對這幾個網站進行分析后,發現這些網站僅有一些熱門游戲的文章語料,一些冷門或者低熱度的游戲,例如“靈魂籌碼”、“奇跡:覺醒”、“死神來了”等,很難在這些網站上找到大量文章語料,如圖所示:

          我們可以發現,“ 奇跡:覺醒”、“靈魂籌碼”的文章語料特別少,數量上不符合我們的要求。 那么有沒有一個比較通用的資源站,它擁有著無比豐富的文章語料,可以滿足我們的需求。

          其實靜下心來想想,這個資源站我們天天都有用到,那就是百度。我們在百度新聞搜索相關游戲,拿到搜索結果列表,這些列表的鏈接的網頁內容幾乎都與搜索結果強相關,這樣我們數據源不夠豐富的問題便輕松解決了。但是此時出現了一個新的問題,并且是一個比較難解決的問題——如何抓取到任意網頁的文章內容?

          因為不同的網站都有不同的頁面結構,我們無法與預知將會爬到哪個網站的數據,并且我們也不可能針對每一個網站都去寫一套爬蟲,那樣的工作量簡直難以想象!但是我們也不能簡單粗暴的將頁面中的所有文字都爬下來,用那樣的語料來進行訓練無疑是噩夢!

          經過與各個網站斗智斗勇、查詢資料與思索之后,終于找到一條比較通用的方案,下面為大家講一講筆者的思路。

          0x3 任意網站的文章語料爬取

          01|提取方法

          1)基于Dom樹正文提取

          2)基于網頁分割找正文塊

          3)基于標記窗的正文提取

          4)基于數據挖掘或機器學習

          5)基于行塊分布函數正文提取

          02|提取原理

          大家看到這幾種是不是都有點疑惑了,它們到底是怎么提取的呢?讓筆者慢慢道來。

          1)基于Dom樹的正文提取:

          這一種方法主要是通過比較規范的HTML建立Dom樹,然后地柜遍歷Dom,比較并識別各種非正文信息,包括廣告、鏈接和非重要節點信息,將非正文信息抽離之后,余下來的自然就是正文信息。

          但是這種方法有兩個問題

          ① 特別依賴于HTML的良好結構,如果我們爬取到一個不按W3c規范的編寫的網頁時,這種方法便不是很適用。

          ② 樹的建立和遍歷時間復雜度、空間復雜度都較高,樹的遍歷方法也因HTML標簽會有不同的差異。

          2) 基于網頁分割找正文塊 :

          這一種方法是利用HTML標簽中的分割線以及一些視覺信息(如文字顏色、字體大小、文字信息等)。

          這種方法存在一個問題:

          ① 不同的網站HTML風格迥異,分割沒有辦法統一,無法保證通用性。

          3) 基于標記窗的正文提?。?/strong>

          先科普一個概念——標記窗,我們將兩個標簽以及其內部包含的文本合在一起成為一個標記窗(比如 <h1>我是h1</h1> 中的“我是h1”就是標記窗內容),取出標記窗的文字。

          這種方法先取文章標題、HTML中所有的標記窗,在對其進行分詞。然后計算標題的序列與標記窗文本序列的詞語距離L,如果L小于一個閾值,則認為此標記窗內的文本是正文。

          這種方法雖然看上去挺好,但其實也是存在問題的:

          ① 需要對頁面中的所有文本進行分詞,效率不高。

          ② 詞語距離的閾值難以確定,不同的文章擁有不同的閾值。

          4)基于數據挖掘或機器學習

          使用大數據進行訓練,讓機器提取主文本。

          這種方法肯定是極好的,但是它需要先有html與正文數據,然后進行訓練。我們在此不進行探討。

          5)基于行塊分布函數正文提取

          對于任意一個網頁,它的正文和標簽總是雜糅在一起。此方法的核心有亮點:① 正文區的密度;② 行塊的長度;一個網頁的正文區域肯定是文字信息分布最密集的區域之一,這個區域可能最大(評論信息長、正文較短),所以同時引進行塊長度進行判斷。

          實現思路:

          ① 我們先將HTML去標簽,只留所有正文,同時留下標簽取出后的所有空白位置信息,我們稱其為Ctext;

          ② 對每一個Ctext取周圍k行(k<5),合起來稱為Cblock;

          ③ 對Cblock去掉所有空白符,其文字總長度稱為Clen;

          ④ 以Ctext為橫坐標軸,以各行的Clen為縱軸,建立坐標系。

          以這個網頁為例: http://www.gov.cn/ldhd/2009-11/08/content_1459564.htm 該網頁的正文區域為145行至182行。


          由上圖可知,正確的文本區域全都是分布函數圖上含有最值且連續的一個區域,這個區域往往含有一個驟升點和一個驟降點。因此,網頁正文抽取問題轉化為了求行塊分布函數上的驟升點和驟降點兩個邊界點,這兩個邊界點所含的區域包含了當前網頁的行塊長度最大值并且是連續的。

          經過大量實驗,證明此方法對于中文網頁的正文提取有較高的準確度,此算法的優點在于,行塊函數不依賴與HTML代碼,與HTML標簽無關,實現簡單,準確率較高。

          主要邏輯代碼如下:

           1# 假設content為已經拿到的html
           2
           3# Ctext取周圍k行(k<5),定為3
           4blocksWidth = 3
           5# 每一個Cblock的長度
           6Ctext_len = []
           7# Ctext
           8lines = content.split('n')
           9# 去空格
          10for i in range(len(lines)):
          11 if lines[i] == ' ' or lines[i] == 'n':
          12 lines[i] = ''
          13# 計算縱坐標,每一個Ctext的長度
          14for i in range(0, len(lines) - blocksWidth):
          15 wordsNum = 0
          16 for j in range(i, i + blocksWidth):
          17 lines[j] = lines[j].replace("\s", "")
          18 wordsNum += len(lines[j])
          19 Ctext_len.append(wordsNum)
          20# 開始標識
          21start = -1
          22# 結束標識
          23end = -1
          24# 是否開始標識
          25boolstart = False
          26# 是否結束標識
          27boolend = False
          28# 行塊的長度閾值
          29max_text_len = 88
          30# 文章主內容
          31main_text = []
          32# 沒有分割出Ctext
          33if len(Ctext_len) < 3:
          34 return '沒有正文'
          35for i in range(len(Ctext_len) - 3):
          36 # 如果高于這個閾值
          37 if(Ctext_len[i] > max_text_len and (not boolstart)):
          38 # Cblock下面3個都不為0,認為是正文
          39 if (Ctext_len[i + 1] != 0 or Ctext_len[i + 2] != 0 or Ctext_len[i + 3] != 0):
          40 boolstart = True
          41 start = i
          42 continue
          43 if (boolstart):
          44 # Cblock下面3個中有0,則結束
          45 if (Ctext_len[i] == 0 or Ctext_len[i + 1] == 0):
          46 end = i
          47 boolend = True
          48 tmp = []
          49
          50 # 判斷下面還有沒有正文
          51 if(boolend):
          52 for ii in range(start, end + 1):
          53 if(len(lines[ii]) < 5):
          54 continue
          55 tmp.append(lines[ii] + "n")
          56 str = "".join(list(tmp))
          57 # 去掉版權信息
          58 if ("Copyright" in str or "版權所有" in str):
          59 continue
          60 main_text.append(str)
          61 boolstart = boolend = False
          62# 返回主內容
          63result = "".join(list(main_text))
          復制代碼
          

          0x4 結語

          至此我們就可以獲取任意內容的文章語料了,但這僅僅是開始,獲取到了這些語料后我們還需要在一次進行清洗、分詞、詞性標注等,才能獲得真正可以使用的語料。

          本處理其實是一個很大的題目,無法用文本處理這個名字來概括,從這里這一章開始,我們直接用子項目名做名稱。

          關鍵詞:html代碼

          下面我們開始一個新的內容,就是從網頁代碼的文本文件中提取文字。網頁代碼,我們一般也叫他html代碼。

          下面我們有一個文本文件,內容如下

          內容很長很長,我們僅僅取出一個屏幕,能做范例就好。

          下面的題目是,從這個代碼文件中,我們提取出要看的內容。為此,我們編寫一個程序做個練習。這個程序的名字叫《網頁代碼中提取文字.py》。

          先開始做第一件事,在不做任何修改的情況下,直接讀取文本文件的內容。

          于是我們編寫了下面一個程序

          閱讀過前面文章的人,這個程序一看就懂,不用再解釋了。運行后,顯示效果如下

          如果讓我們從這段代碼中讀出里面的中文內容,我相信是非常困難的。

          下面研究的課題就是,把中間有用的中文部分內容挑選出來,其他的代碼部分去掉,還要盡量保持應該保持的段落,最后有條件的話,再把內容進行一下加工,最后保持文章的主體部分。總之,內容多多如何處理呢?

          首先,我們將研究第一個問題,了解網頁代碼的基本知識??聪聢D

          第一張圖片,是一個網頁的基本框架。第二張圖片,我們對他進行了標注,綠色部分是網頁的頭部信息,紅色部分是網頁中的實質內容。黃色的圈圈,就是網頁的全部代碼。

          網頁的代碼通常用尖括號把它標注出來,他有很多的特殊符號,本格式如下

          <html></html>這兩個是匹配的,中間就是網頁代碼具體的內容。

          <body></body>這兩個也是匹配的,中間是代碼中文章體內容的具體部分。

          <p></p>這兩個也是匹配的,中間是文章段落的具體部分。

          HTML語言,大部分內容都是這樣配對的,個別的不配對。

          由于內容實在太多,我們僅做最簡單的介紹。只要掌握一個規律就可以啦,這個規律就是,代碼一般都是用尖括號括起來的。

          需要說明的是,網頁代碼我們可以隨便打開一個網頁,查看源代碼就可以看到。我們研究的是通過取出文字的內容來研究文本處理的方法。


          主站蜘蛛池模板: 一本一道波多野结衣AV一区| 国产伦精品一区二区三区免费下载| 国产在线精品一区二区三区直播| 亚洲AV日韩综合一区| 蜜桃臀无码内射一区二区三区| 亚洲国产精品一区二区成人片国内 | 国产乱码精品一区二区三区麻豆| 国产经典一区二区三区蜜芽| 国产精品揄拍一区二区| 亚洲一区二区三区在线网站| 91久久精品国产免费一区| 精品亚洲A∨无码一区二区三区| 中文字幕一区二区三区精彩视频 | 精品一区二区视频在线观看 | 精品视频一区二区三区四区 | 成人精品一区久久久久| 国产日韩精品一区二区在线观看播放| 国产日韩精品一区二区在线观看| 国产成人一区二区三区免费视频| 国产一区二区三区在线免费| 国产伦精品一区二区免费| 中文字幕Av一区乱码| 色狠狠一区二区三区香蕉| 呦系列视频一区二区三区| 海角国精产品一区一区三区糖心 | 精品免费AV一区二区三区| 精品国产毛片一区二区无码| 奇米精品一区二区三区在线观看| 在线中文字幕一区| 精品国产日韩亚洲一区在线| 动漫精品专区一区二区三区不卡| 中文字幕精品亚洲无线码一区应用| 日本不卡免费新一区二区三区| 国产福利91精品一区二区三区| 国产日韩视频一区| 亚洲国产精品一区二区久久hs| 亚洲日韩国产一区二区三区在线| 男人的天堂精品国产一区| 国产AV午夜精品一区二区三区| 中文字幕一区日韩精品| 动漫精品专区一区二区三区不卡|