標籤:web
“web抓取”是一個術語,即利用程式下載並處理來自web的內容。
▎在python中,有幾個模組能讓抓取網頁變得很容易。
webbrowser:python內建,開啟遊覽器擷取指定頁面。
requests:從網際網路上下載檔案和網頁。
Beautiful Soup:解析HTML,即網頁編寫的格式。
selenium:啟動並控制一個web遊覽器。selenium能夠填寫表單,並類比滑鼠在這個遊覽器中點擊。
webbrowser模組
webbrowser模組的open()函數可以啟動一個新遊覽器,開啟指定的URL。
>>> import webbrowser>>> webbrowser.open(‘http://www.baidu.com‘)
requests模組
requests模組能很容易從web下載檔案,不必擔心一些複雜的問題,諸如網路錯誤、串連問題和資料壓縮。
requests模組不是python內建的,所以必須先通過pip安裝。
編寫requests模組是因為python的urllib2模組用起來太複雜。如果需要從web下載東西,還是使用requests模組更方便。
[[email protected] ~]# pip install requestsCollecting requests Downloading requests-2.18.2-py2.py3-none-any.whl (88kB) 100% |████████████████████████████████| 92kB 75kB/s Collecting chardet<3.1.0,>=3.0.2 (from requests) Downloading chardet-3.0.4-py2.py3-none-any.whl (133kB) 100% |████████████████████████████████| 143kB 75kB/s Collecting urllib3<1.23,>=1.21.1 (from requests) Downloading urllib3-1.22-py2.py3-none-any.whl (132kB) 100% |████████████████████████████████| 133kB 21kB/s Collecting certifi>=2017.4.17 (from requests) Downloading certifi-2017.7.27.1-py2.py3-none-any.whl (349kB) 100% |████████████████████████████████| 358kB 27kB/s Collecting idna<2.6,>=2.5 (from requests) Downloading idna-2.5-py2.py3-none-any.whl (55kB) 100% |████████████████████████████████| 61kB 36kB/s Installing collected packages: chardet, urllib3, certifi, idna, requestsSuccessfully installed certifi-2017.7.27.1 chardet-3.0.4 idna-2.5 requests-2.18.2 urllib3-1.22
requests.get()函數接受一個要下載的URL字串。通過在requests.get()的傳回值上調用type(),返回一個Response對象,其中包含了web伺服器對請求做出的響應。
通過檢查Response對象的status_code屬性,可以瞭解對這個網頁的請求是否成功。如果該值等於requests.codes.ok,那麼一切都好。
如果請求成功,下載的頁面就作為一個字串,儲存在Response對象的text變數中。
>>> import requests>>> res=requests.get(‘https://wkbos.bdimg.com/v1/wenku1//......=2017-07-30T13:23:41Z‘)>>> type(res)<class ‘requests.models.Response‘>>>> res.status_code==requests.codes.okTrue>>> len(res.text)25663>>> print(res.text[:100])1. 閱讀須知文中使用 作為會命令列中的輸出資訊的首碼 對於不清楚用用途的函數可以在解譯器下面輸入 help(函數名)來擷取相關資訊 另外,內建的文檔和goo
除了status_code屬性檢查是否成功,還有一種簡單的方法,就是在Response對象上調用raise_for_status()方法。如果下載檔案出錯,將拋出異常;如果下載成功,就什麼也不做。
raise_for_status()方法是一種很好的方式,確保程式在下載失敗時停止。可以用try和except語句將raise_for_status()程式碼封裝裹起來,處理這一錯誤,不讓程式崩潰。
總是在調用requests.get()之後再調用raise_for_status()。確保下載確實成功,然後再讓程式繼續。
>>> res=requests.get(‘http://nostarch.com‘)>>> res.raise_for_status()Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/site-packages/requests/models.py", line 937, in raise_for_status raise HTTPError(http_error_msg, response=self)requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: http://nostarch.com/
將下載的檔案儲存到硬碟,可以用標準的open()函數和write()方法,但必須用“寫二進位(wb)”模式開啟該檔案,作為open()的第二參數。
即使該頁面是純文字的,也需要寫入位元據,而不是文本資料,目的是為了儲存該文本中的“unicode編碼”。
為了將web頁面寫入到一個檔案,可以用for迴圈和Response對象的iter_content()方法。
>>> import requests>>> res=requests.get(‘http://www.gutenberg.org/cache/epub/1112/pg1112.txt‘)>>> res.raise_for_status()>>> playFile=open(‘123.txt‘,‘wb‘)>>> for text in res.iter_content(100000):... playFile.write(text)... >>> playFile.close()
BeautifulSoup模組
HTML簡介
超文字標記語言 (HTML)(HTML)是編寫web頁面的格式。
HTML中有許多不同的標籤。有一些標籤具有額外的特性,在角括弧內以“屬性”的方式展現。
某些元素具有id屬性,可以用來在頁面上唯一地確定該元素。
程式可以根據元素的id屬性來尋找它。開發人員要弄清楚元素的id屬性,這是編寫web抓取程式常見的任務。
不要用Regex來解析HTML。在一個字串中定位特定的一段HTML,這似乎很適合使用Regex。但是,不建議這麼做。HTML的格式可以有很多不同的方式,並且仍然被認為是有效HTML,但嘗試用Regex來捕捉所有這些可能的變化,將非常繁瑣,並且容易出錯。專門用於解析HTML的模組,諸如Beautiful Soup,將更不容易導致缺陷。
Beautiful Soup是一個模組,用於從HTML頁面中提取資訊。它的名稱是bs4,通過pip安裝(pip install beautifulsoup4),匯入使用命令import bs4。
針對要尋找的元素,調用method()方法,傳入一個字串作為CSS“選取器”。選取器就像Regex:它們指定了要尋找的模式。
[[email protected] ~]# pip install beautifulsoup4Collecting beautifulsoup4 Downloading beautifulsoup4-4.6.0-py2-none-any.whl (86kB) 100% |████████████████████████████████| 92kB 540kB/s Installing collected packages: beautifulsoup4Successfully installed beautifulsoup4-4.6.0
>>> import requests,bs4>>> res=requests.get(‘http://www.baidu.com‘)>>> res.raise_for_status()>>> bs=bs4.BeautifulSoup(res.text,‘html.parser‘)>>> type(bs)<class ‘bs4.BeautifulSoup‘>
▎CSS選取器舉例:
soup.select(‘div‘) 所有名為<div>的元素
soup.select(‘#author‘) 帶有id屬性為author的元素
soup.select(‘p#author‘) 所有id屬性為author的元素,只要它也在一個<p>元素之內
soup.select(‘.notice‘) 所有使用CSS class屬性名稱為notice的元素
soup.select(‘div span‘) 所有在<div>元素之內的<span>元素
soup.select(‘div>span‘) 所有直接在<div>元素之內的<span>元素,中間沒有其他元素
soup.select(‘input[name]‘) 所有名為<input>,並有一個name屬性,其值無所謂的元素
soup.select(‘input[type="button"]‘) 所有名為<input>,並有一個type屬性,其值為button的元素
不同的選取器模式可以組合起來,形成複雜的匹配。
select()方法將返回一個Tag對象的列表,這是Beautiful Soup表示一個HTML元素的方式。
針對BeautifulSoup對象的HTML的每次匹配,列表中都有一個Tag對象。
Tag值可以傳遞給str()函數,顯示它們代表HTML標籤。
Tag值也可以有attrs屬性,它將該Tag的所有HTML 屬性作為一個字典。
Tag對象的get()方法讓我們很容易從元素中擷取屬性值。向該方法傳入一個屬性名稱的字串,它將返回該屬性的值。
>>> import requests,bs4>>> exampleFile=requests.get(‘http://www.baidu.com‘)>>> exampleBS=bs4.BeautifulSoup(exampleFile.text,‘html.parser‘)>>> elems=exampleBS.select(‘a‘)>>> type(elems)<type ‘list‘>>>> len(elems)11>>> type(elems[0])<class ‘bs4.element.Tag‘>>>> elems[0].getText()u‘\xe6\x96\xb0\xe9\x97\xbb‘>>> str(elems[0])‘<a class="mnav" href="http://news.baidu.com" name="tj_trnews">\xc3\xa6\xc2\x96\xc2\xb0\xc3\xa9\xc2\x97\xc2\xbb</a>‘>>> elems[0].attrs{u‘href‘: u‘http://news.baidu.com‘, u‘name‘: u‘tj_trnews‘, u‘class‘: [u‘mnav‘]}
selenium模組
selenium模組讓python直接控制遊覽器,實際點選連結,填寫登入資訊,幾乎就像是有一個人類使用者在與頁面互動。
不推薦使用selenium模組下載檔案,會有點慢,並且難以在後台運行。
selenium模組的匯入方式:from selenium import webdriver。
使用FireFox方法,首先要在系統裡安裝Firefox遊覽器。
[[email protected] ~]# pip install seleniumCollecting selenium Downloading selenium-3.4.3-py2.py3-none-any.whl (931kB) 100% |████████████████████████████████| 942kB 46kB/s Installing collected packages: seleniumSuccessfully installed selenium-3.4.3
>>> from selenium import webdriver>>> browser=webdriver.FireFox()>>> type(browser)<class ‘selenium.webdriver.firefox.webdriver.WebDriver‘>>>> browser.get(‘http://www.baidu.com‘)
WebDriver對象有好幾種方法,用於在頁面中尋找元素。它們被分成find_element_*和find_elements_*方法。
find_element_*方法返回一個WebElement對象,代表頁面中匹配查詢的第一個元素。
find_elements_*方法返回WebElement_*對象的列表,包含頁面中所有匹配的元素。
▎WebDriver方法,用於尋找元素:
browser.find_element_by_class_name(name) 使用CSS類name的元素
browser.find_elements_by_class_name(name)
browser.find_element_by_css_selector(selector) 匹配CSS selector的元素
browser.find_elements_by_css_selector(selector)
browser.find_element_by_id(id) 匹配id屬性值的元素
browser.find_elements_by_id(id)
browser.find_element_by_link_text(text) 完全符合提供的text的<a>元素
browser.find_elements_by_link_text(text)
browser.find_element_by_partial_link_text(text) 包含提供的text的<a>元素
browser.find_elements_by_partial_link_text(text)
browser.find_element_by_name(name) 匹配name屬性值的元素
browser.find_elements_by_name(name)
browser.find_element_by_tag_name(name) 匹配標籤name的元素
browser.find_elements_by_tag_name(name) (大小寫無關,<a>元素匹配‘a’和‘A’)
除了*_by_tag_name()方法,所有方法的參數都是區分大小寫。如果沒有元素匹配,將會拋出NoSuchElement異常。
▎Webement的屬性和方法:
tag_name 標籤名,例如‘a’表示<a>元素
get_attribute(name) 該元素name屬性的值
text 該元素內的文本,例如<span>hello</span>中的‘hello’
clear() 對於文字欄位或文本地區元素,清除其中輸入的文本
is_displayed() 如果該元素可見,返回True,否則返回False
is_enabled() 對於輸入元素,如果該元素啟用,返回True,否則返回False
is_selected() 對於複選框或單選框元素,如果該元素被選中,返回True,否則返回False
location 一個字典,包含鍵x和y,表示該元素在頁面上的位置
find_element_*和find_elements_*方法返回的WebElement對象有一個click()方法,類比滑鼠在該元素上點擊。
這個方法用於連結跳轉,選擇選項按鈕,點擊提交按鈕,或者觸發該元素被滑鼠點擊時發生的任何事情。
向web頁面的文字欄位發送擊鍵,只要找到那個文字欄位的<input>或<textarea>元素,然後調用send_keys()方法。
selenium有一個模組,針對不能用字串值輸入的鍵盤擊鍵。它的功能非常類似逸出字元。
這些值儲存在selenium.webdriver.common.keys模組的屬性中。由於這個模組名較長,建議from selenium.webdriver.common.keys import Keys。
▎selenium.webdriver.common.keys模組中常用的變數:
Keys.DOWN,Keys.UP,Keys.LEFT,Keys.RIGHT 鍵盤方向鍵
Keys.ENTER,Keys.RETURN 斷行符號和換行鍵
Keys.HOME,Keys.END,Keys.PAGE_DOWN,Keys.PAGE_UP HOME鍵、END鍵、Page Up鍵、Page Down鍵
Keys.ESCAPE,Keys.BACK_SPACE,Keys.DELETE Esc、Backspace和Delete鍵
Keys.F1,Keys.F2,...,Keys.F12 鍵盤頂部的F1到F12鍵
Keys.TAB Tab鍵
▎利用以下的方法,selenium也可以類比點擊各種遊覽器按鈕:
browser.back()點擊“返回”按鈕。
browser.forward()點擊“前進”按鈕。
browser.refresh()點擊[重新整理] 按鈕。
browser.quit()點擊“關閉視窗”按鈕。
本文出自 “A man & A computer” 部落格,請務必保留此出處http://juispan.blog.51cto.com/943137/1952156
從web抓取資訊