一篇我們介紹了如何解析CSV和JSON數據:如何解析互聯網數據:CSV和JSON篇,今天我們將介紹如何解析HTML和XML數據。
今天的介紹能夠幫助你輕而易舉地從網頁中(比如下面的中航電子的2017年一季度交易數據)提取自己想要的數據:
準備
在Python中可以解析html和xml數據的軟件包很多,今天我們介紹的是lxml,先安裝:
$ pip install lxml
如果不熟悉pip的使用,可以參考另一篇文章:如何管理python軟件包。
解析HTML數據
首先,回顧一下HTML的一些基本概念:
標簽/tag:比如<html>, <h1>, <head>...一般成對出現,例如開始標簽<html>和結束標簽</html>
元素/element:開始標簽到結束標簽整段代碼,標簽對之間的即為內容(content)
屬性/attribute:標簽可擁有key=value形式的屬性,比如<div class="header">...</div>
簡單地理解,HTML網頁就是由一組元素構成的一個集合。另外,大多數HTML標簽是可以嵌套的,因此元素可以包含一系列子元素。有了這些概念做基礎,我們將能夠很容易理解軟件包lxml的使用。實際上,在lxml里面,每個HTML元素對應一個lxml.html.HtmlElement對象,該對象提供一組標準的方法取訪問包含在該元素內部的數據,比如屬性、內容和子元素等。
例子
考察下面的鏈接,它提供中航電子在2017年第一季度的交易數據,我們打算從里面提取一些數據:
>>> url = "http://quotes.money.163.com/trade/lsjysj_600372.html?year=2017&season=1"
先把該網頁爬取下來:
>>> import urllib2
>>> rsp = urllib2.urlopen(url).read()
>>> print rsp[0:15]
<!DOCTYPE html>
將字符串rsp轉換成HtmlElement對象:
>>> from lxml import html
>>> doc = html.document_fromstring(rsp)
>>> type(doc)
<class 'lxml.html.HtmlElement'>
>>> doc.tag
'html'
所以其實doc就是一個html元素,它包含一些元素,比如head, body, link, div...
比如,如果你想提取該網頁里面所有的鏈接(links):
>>> links = [ link for link in doc.iterlinks() ]
>>> len(links)
106
>>> links[0]
(<Element link at 0x1029179f0>, 'href', 'http://img1.cache.netease.com/f2e/finance/gegu/s.1064000.css', 0)
>>> links[0][2]
'http://img1.cache.netease.com/f2e/finance/gegu/s.1064000.css'
如果你想查看元素直接包含哪些子元素,可以調用getchildren()方法:
>>> doc.getchildren()
[<Element head at 0x10299a0a8>, <Element body at 0x10299a470>]
對嵌套很深的元素,如果熟悉xpath表達式,最直接的辦法是調用xpath(...)方法:
>>> [ td.text for td in doc.xpath('/html/body/div[2]/div[4]/table/tr[1]/td')]
['2017-03-31', '19.02', '19.50', '19.02', '19.30', '0.36', '1.90', '102,212', '19,747', '2.53', '0.58']
此外,還可以通過find, findall, find_class, get_element_by_id等方法查找目標元素,比如:
>>> [ td.text for td in doc.findall('./body/div[2]/div[4]/table/tr[1]/td')]
['2017-03-31', '19.02', '19.50', '19.02', '19.30', '0.36', '1.90', '102,212', '19,747', '2.53', '0.58']
如果元素有屬性,提取屬性值也很方便,比如:
>>> form = doc.forms[0]
>>> form.tag
'form'
>>> form.attrib
{'action': '/trade/lsjysj_600372.html', 'id': 'date'}
>>> form.keys()
['id', 'action']
>>> form.get('action')
'/trade/lsjysj_600372.html'
>>> form.items()
[('id', 'date'), ('action', '/trade/lsjysj_600372.html')]
'>>> form.form_values()
[('year', '2017'), ('season', '1')]
>>> form.method
'GET'
做為一個完整的例子,下面的腳本就是爬取中航電子在2017年第一季度的數據:
輸出效果:
(test) $ head -3 600372.csv
日期;開盤價;最高價;最低價;收盤價;漲跌額;漲跌幅(%);成交量(手);成交金額(萬元);振幅(%);換手率(%)
2017-03-31;19.02;19.50;19.02;19.30;0.36;1.90;102,212;19,747;2.53;0.58
2017-03-31;19.02;19.50;19.02;19.30;0.36;1.90;102,212;19,747;2.53;0.58
解析xml數據
xml的格式和HTML類似,也是由標簽構成的,但是要比HTML文件簡單許多,看下面的xml文件片段處理:
>>> xmlstr="""\
... <target name="run" depends="jar">
... <java fork="true" classname="${main-class}">
... <classpath>
... <path refid="classpath"/>
... <path refid="application"/>
... </classpath>
... </java>
... </target>"""
>>> from lxml import etree
第一步是獲取根節點:
>>> root = etree.fromstring(xmlstr)
>>> root.tag
'target'
如果要提取節點屬性:
>>> root.items()
[('name', 'run'), ('depends', 'jar')]
>>> root.keys()
['name', 'depends'
>>> root.get("name")
'run'
>>> root.values()
['run', 'jar']
可以使用find, xpath等方法去獲取和查找子節點:
>>> java = root.find("./java")
>>> java.tag
'java'
>>> java.keys()
['fork', 'classname']
>>> [ path.get("refid") for path in root.xpath("http://path")]
['classpath', 'application']
lxml軟件的功能很強大,如果有興趣進一步了解,可以查看官方文檔:
http://lxml.de/index.html
今天就寫這么,歡迎大家留言、評論和關注。
Python寫爬蟲工具在現在是一種司空見慣的事情,每個人都希望能夠寫一段程序去互聯網上扒一點資料下來,用于數據分析或者干點別的事情。
我們知道,爬蟲的原理無非是把目標網址的內容下載下來存儲到內存中,這個時候它的內容其實是一堆HTML,然后再對這些HTML內容進行解析,按照自己的想法提取出想要的數據,所以今天我們主要來講四種在Python中解析網頁HTML內容的方法,各有千秋,適合在不同的場合下使用。
首先我們隨意找到一個網址,這時我腦子里閃過了豆瓣這個網站。嗯,畢竟是用Python構建的網站,那就拿它來做示范吧。
我們找到了豆瓣的Python爬蟲小組主頁,看起來長成下面這樣。
讓我們用瀏覽器開發者工具看看HTML代碼,定位到想要的內容上,我們想要把討論組里的帖子標題和鏈接都給扒出來。
通過分析,我們發現實際上我們想要的內容在整個HTML代碼的 <table class="olt">這個區域里,那我們只需要想辦法把這個區域內的內容拿出來就差不多了。
現在開始寫代碼。
正則表達式通常被用來檢索、替換那些符合某個模式的文本,所以我們可以利用這個原理來提取我們想要的信息。
參考以下代碼。
在代碼第6行和第7行,需要手動指定一下header的內容,裝作自己這個請求是瀏覽器請求,否則豆瓣會視為我們不是正常請求會返回HTTP 418錯誤。
在第7行我們直接用requests這個庫的get方法進行請求,獲取到內容后需要進行一下編碼格式轉換,同樣是因為豆瓣的頁面渲染機制的問題,正常情況下,直接獲取requests content的內容即可。
Python模擬瀏覽器發起請求并解析內容代碼:
url = 'https://www.douban.com/group/491607/'
headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0"}
response = requests.get(url=url,headers=headers).content.decode('utf-8')
正則的好處是編寫麻煩,理解不容易,但是匹配效率很高,不過時至今日有太多現成的HTMl內容解析庫之后,我個人不太建議再手動用正則來對內容進行匹配了,費時費力。
主要解析代碼:
re_div = r'<table\s+class=\"olt\">[\W|\w]+</table>'
pattern = re.compile(re_div)
content = re.findall(pattern, str(response))
re_link = r'<a .*?>(.*?)</a>'
mm = re.findall(re_link, str(content), re.S|re.M)
urls=re.findall(r"<a.*?href=.*?<\/a>", str(content), re.I|re.S|re.M)
這個庫其實是我個人最喜歡的庫,作則是編寫requests庫的網紅程序員 Kenneth Reitz,他在requests的基礎上加上了對html內容的解析,就變成了requests-html這個庫了。
下面我們來看看范例:
我喜歡用requests-html來解析內容的原因是因為作者依據幫我高度封裝過了,連請求返回內容的編碼格式轉換也自動做了,完全可以讓我的代碼邏輯簡單直接,更專注于解析工作本身。
主要解析代碼:
links = response.html.find('table.olt', first=True).find('a')
安裝途徑: pip install requests-html
大名鼎鼎的 BeautifulSoup庫,出來有些年頭了,在Pyhton的HTML解析庫里屬于重量級的庫,其實我評價它的重量是指比較臃腫,大而全。
還是來先看看代碼。
soup = BeautifulSoup(response, 'html.parser')
links = soup.findAll("table", {"class": "olt"})[0].findAll('a')
BeautifulSoup解析內容同樣需要將請求和解析分開,從代碼清晰程度來講還將就,不過在做復雜的解析時代碼略顯繁瑣,總體來講可以用,看個人喜好吧。
安裝途徑: pip install beautifulsoup4
lxml這個庫同時 支持HTML和XML的解析,支持XPath解析方式,解析效率挺高,不過我們需要熟悉它的一些規則語法才能使用,例如下圖這些規則。
來看看如何用XPath解析內容。
主要解析代碼:
content = doc.xpath("//table[@class='olt']/tr/td/a")
如上圖,XPath的解析語法稍顯復雜,不過熟悉了語法的話也不失為一種優秀的解析手段,因為。
安裝途徑: pip install lxml
除了以上介紹到幾種網頁內容解析方式之外還有很多解析手段,在此不一一進行介紹了。
寫一個爬蟲,最重要的兩點就是如何抓取數據,如何解析數據,我們要活學活用,在不同的時候利用最有效的工具去完成我們的目的。
因篇幅有限,以上四種方式的代碼就不貼在文章里了,歡迎給我私信獲取。
歡迎關注我 “紙飛機編程”,獲取更多有趣的python教程信息。
ython爬蟲。
大家好,我是Python的Python爬蟲。今天給大家演示一個網絡爬蟲的源碼,就是用Python來解析html就是前端的數據。首先可以看到前面有一個支付串,支付串里包含的內容是前端的數據,它有html標簽、Python標簽、玻璃標簽和html標簽。
然后要通過網絡劃重來提取標簽語的數據。首先寫了一個Python對象的方法。然后把這個文件,文件用PythonL解析器來解析,最后再輸出這個文件。輸出文件之后再打印這個文件的格式,來看一下具體效果。
可以看到html文件已經打印成功了,它的類型是beautiful soul beautiful Python類型。然后再來獲取一下當前的標簽名,可以看到它或許是title標簽里的內容,可以看到title標簽里的內容是b。然后看打印的結果和這個一分為二。再運行一下,可以看到標簽內容打印的結果是一致的。然后再獲取一下當前的標簽名,看一下打印的內容是否一致。再運行一下,這里出現了一個錯誤。是因為這里有一行代碼,有一個漢字沒有注視掉。
再運行一下,可以看到這個標簽名還是打印出來了,它和這里的內容是一樣的。再輸出一下標簽,標簽里面的內容。可以看到p標簽點內容就可以打印出來了。然后獲取一下所有的a標簽,可以看到一標簽的內容就打印出來了。然后讀取一下所有的a標簽,看一下剛才的a標簽一共有一個兩個三個在,第三個在這邊,a標簽。
其中a標簽和a標簽是一樣的,所以一共只打印了一個A4標簽。然后查找一下,a D為Python的標簽。打印一下標a d n minus 三的標簽。可以看到a d 為mix三的標簽,已經顯示出來了。最后打印所的內容。
把前面都做四個,可以看到標簽里面的內容都出來了,看一下是不是對的。可以看到這個內容和這都對的上。最后一句,最后一句的內容就對的上。今天演示的網絡花叢的視頻就到這里,謝謝大家的收看。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。