對Beautifulsoup和selenium用法的簡單介紹

來源:互聯網
上載者:User

Beautifulsoup和selenium的簡單使用

requests庫的複習

好久沒用requests了,因為一會兒要寫個簡單的爬蟲,所以還是隨便寫一點複習下。

import requestsr = requests.get('https://api.github.com/user', auth=('haiyu19931121@163.com', 'Shy18137803170'))print(r.status_code)  # 狀態代碼200print(r.json())  # 返回json格式print(r.text)  # 返迴文本print(r.headers)  # 頭資訊print(r.encoding)  # 編碼方式,一般utf-8# 當寫入檔案比較大時,避免記憶體耗盡,可以一次寫指定的位元組數或者一行。# 一次讀一行,chunk_size=512為預設值for chunk in r.iter_lines():print(chunk)# 一次讀取一塊,大小為512for chunk in r.iter_content(chunk_size=512):print(chunk)

注意iter_linesiter_content返回的都是位元組資料,若要寫入檔案,不管是文本還是圖片,都需要以wb的方式開啟。

Beautifulsoup的使用

進入正題,早就聽說這個著名的庫,以前寫爬蟲用Regex雖然不麻煩,但有時候會匹配不準確。使用Beautifulsoup可以準確從HTML標籤中提取資料。雖然是慢了點,但是簡單好使呀。

from bs4 import BeautifulSouphtml_doc = """<html><head><title>The Dormouse's story</title></head><body><p class="title"><b>The Dormouse's story</b></p><p class="story">Once upon a time there were three little sisters; and their names were<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;and they lived at the bottom of a well.</p><p class="story">...</p>"""# 就注意一點,第二個參數指定解析器,必須填上,不然會有警告。推薦使用lxmlsoup = BeautifulSoup(html_doc, 'lxml')

緊接著上面的代碼,看下面一些簡單的操作。使用點屬性的行為,會得到第一個尋找到的合格資料。是find方法的簡寫。

soup.asoup.find('p')

上面的兩句是等價的。

# soup.body是一個Tag對象。是body標籤中所有html代碼print(soup.body)
<body><p class="title"><b>The Dormouse's story</b></p><p class="story">Once upon a time there were three little sisters; and their names were<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;and they lived at the bottom of a well.</p><p class="story">...</p></body>
# 擷取body裡所有文本,不含標籤print(soup.body.text)# 等同於下面的寫法soup.body.get_text()# 還可以這樣寫,strings是所有文本的產生器for string in soup.body.strings:print(string, end='')
The Dormouse's storyOnce upon a time there were three little sisters; and their names wereElsie,Lacie andTillie;and they lived at the bottom of a well....
# 獲得該標籤裡的文本。print(soup.title.string)
The Dormouse's story
# Tag對象的get方法可以根據屬性的名稱獲得屬性的值,此句表示得到第一個p標籤裡class屬性的值print(soup.p.get('class'))# 和下面的寫法等同print(soup.p['class'])
['title']
# 查看a標籤的所有屬性,以字典形式給出print(soup.a.attrs)
{'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}
# 標籤的名稱soup.title.name
title

find_all

使用最多的當屬find_all / find方法了吧,前者尋找所有合格資料,返回一個列表。後者則是這個列表中的第一個資料。find_all有一個limit參數,限制列表的長度(即尋找合格資料的個數)。當limit=1其實就成了find方法 。

find_all同樣有簡寫方法。

soup.find_all('a', id='link1')soup('a', id='link1')

上面兩種寫法是等價的,第二種寫法便是簡寫。

find_all(self, name=None, attrs={}, recursive=True, text=None,             limit=None, **kwargs)

name

name就是想要搜尋的標籤,比如下面就是找到所有的p標籤。不僅能填入字串,還能傳入Regex、列表、函數、True。

# 傳入字串soup.find_all('p')# 傳入Regeximport re# 必須以b開頭for tag in soup.find_all(re.compile("^b")):print(tag.name)# body# b# 含有t就行for tag in soup.find_all(re.compile("t")):print(tag.name)# html# title# 傳入列表表示,一次尋找多個標籤soup.find_all(["a", "b"])# [<b>The Dormouse's story</b>,#  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

傳入True的話,就沒有限制,什麼都尋找了。

recursive

調用tag的 find_all() 方法時,Beautiful Soup會檢索當前tag的所有子孫節點,如果只想搜尋tag的直接子節點,可以使用參數 recursive=False

# title不是html的直接子節點,但是會檢索其下所有子孫節點soup.html.find_all("title")# [<title>The Dormouse's story</title>]# 參數設定為False,只會找直接子節點soup.html.find_all("title", recursive=False)# []# title就是head的直接子節點,所以這個參數此時無影響a = soup.head.find_all("title", recursive=False)# [<title name="good">The Dormouse's story</title>]

keyword和attrs

使用keyword,加上一個或者多個限定條件,縮小尋找範圍。

# 查看所有id為link1的p標籤soup.find_all('a', id='link1')

如果按類尋找,由於class關鍵字Python已經使用。可以用class_,或者不指定關鍵字,又或者使用attrs填入字典。

soup.find_all('p', class_='story')soup.find_all('p', 'story')soup.find_all('p', attrs={"class": "story"})

上面三種方法等價。class_可以接受字串、Regex、函數、True。

text

搜尋文本值,好像使用string參數也是一樣的結果。

a = soup.find_all(text='Elsie')# 或者,4.4以上版本請使用texta = soup.find_all(string='Elsie')

text參數也可以接受字串、Regex、True、列表。

CSS選取器

還能使用CSS選取器呢。使用select方法就好了,select始終返回一個列表。

列舉幾個常用的操作。

# 所有div標籤soup.select('div')# 所有id為username的元素soup.select('.username')# 所有class為story的元素soup.select('#story')# 所有div元素之內的span元素,中間可以有其他元素soup.select('div span')# 所有div元素之內的span元素,中間沒有其他元素soup.select('div > span')# 所有具有一個id屬性的input標籤,id的值無所謂soup.select('input[id]')# 所有具有一個id屬性且值為user的input標籤soup.select('input[id="user"]')# 搜尋多個,class為link1或者link2的元素都符合soup.select("#link1, #link2")

一個爬蟲小例子

上面介紹了requests和beautifulsoup4的基本用法,使用這些已經可以寫一些簡單的爬蟲了。來試試吧。

此例子來自《Python編程快速上手——讓繁瑣的工作自動化》[美] AI Sweigart

這個爬蟲會批量下載XKCD漫畫網的圖片,可以指定下載的頁面數。

import osimport requestsfrom bs4 import BeautifulSoup# exist_ok=True,若檔案夾已經存在也不會報錯os.makedirs('xkcd')url = 'https://xkcd.com/'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '  'Chrome/57.0.2987.98 Safari/537.36'}def save_img(img_url, limit=1):    r = requests.get(img_url, headers=headers)    soup = BeautifulSoup(r.text, 'lxml')try:        img = 'https:' + soup.find('div', id='comic').img.get('src')except AttributeError:print('Image Not Found')else:print('Downloading', img)        response = requests.get(img, headers=headers)with open(os.path.join('xkcd', os.path.basename(img)), 'wb') as f:for chunk in response.iter_content(chunk_size=1024*1024):                f.write(chunk)# 每次下載一張圖片,就減1limit -= 1# 找到上一張圖片的網址if limit > 0:try:            prev = 'https://xkcd.com' + soup.find('a', rel='prev').get('href')except AttributeError:print('Link Not Exist')else:            save_img(prev, limit)if __name__ == '__main__':    save_img(url, limit=20)print('Done!')
Downloading Downloading Downloading Downloading Downloading Downloading Downloading Downloading Downloading ...Done!

多線程下載

單線程的速度有點慢,比如可以使用多線程,由於我們在擷取prev的時候,知道了每個網頁的網址是很有規律的。它像這樣。只是最後的數字不一樣,所以我們可以很方便地使用range來遍曆。

import osimport threadingimport requestsfrom bs4 import BeautifulSoupos.makedirs('xkcd')headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '  'Chrome/57.0.2987.98 Safari/537.36'}def download_imgs(start, end):for url_num in range(start, end):        img_url = 'https://xkcd.com/' + str(url_num)        r = requests.get(img_url, headers=headers)        soup = BeautifulSoup(r.text, 'lxml')try:            img = 'https:' + soup.find('div', id='comic').img.get('src')except AttributeError:print('Image Not Found')else:print('Downloading', img)            response = requests.get(img, headers=headers)with open(os.path.join('xkcd', os.path.basename(img)), 'wb') as f:for chunk in response.iter_content(chunk_size=1024 * 1024):                    f.write(chunk)if __name__ == '__main__':# 下載從1到30,每個線程下載10個threads = []for i in range(1, 30, 10):        thread_obj = threading.Thread(target=download_imgs, args=(i, i + 10))        threads.append(thread_obj)        thread_obj.start()# 阻塞,等待線程執行結束都會等待for thread in threads:        thread.join()# 所有線程下載完畢,才列印print('Done!')

來看下結果吧。

初步瞭解selenium

selenium用來作自動化測試。使用前需要下載驅動,我只下載了Firefox和Chrome的。網上隨便一搜就能下載到了。接下來將下載下來的檔案其複製到將安裝目錄下,比如Firefox,將對應的驅動程式放到C:\Program Files (x86)\Mozilla Firefox,並將這個路徑添加到環境變數中,同理Chrome的驅動程式放到C:\Program Files (x86)\Google\Chrome\Application並將該路徑添加到環境變數。最後重啟IDE開始使用吧。

類比百度搜尋

下面這個例子會開啟Chrome瀏覽器,訪問百度首頁,類比輸入The Zen of Python,隨後點擊百度一下,當然也可以用斷行符號代替。Keys下是一些不能用字串表示的鍵,比如方向鍵、Tab、Enter、Esc、F1~F12、Backspace等。然後等待3秒,頁面跳轉到知乎首頁,接著返回到百度,最後退出(關閉)瀏覽器。

from selenium import webdriverfrom selenium.webdriver.common.keys import Keysimport timebrowser = webdriver.Chrome()# Chrome開啟百度首頁browser.get('https://www.baidu.com/')# 找到輸入地區input_area = browser.find_element_by_id('kw')# 地區內填寫內容input_area.send_keys('The Zen of Python')# 找到"百度一下"search = browser.find_element_by_id('su')# 點擊search.click()# 或者按下斷行符號# input_area.send_keys('The Zen of Python', Keys.ENTER)time.sleep(3)browser.get('https://www.zhihu.com/')time.sleep(2)# 返回到百度搜尋browser.back()time.sleep(2)# 退出瀏覽器browser.quit()

send_keys類比輸入內容。可以使用element的clear()方法清空輸入。一些其他類比點擊瀏覽器按鈕的方法如下

browser.back()  # 返回按鈕browser.forward() # 前進按鈕browser.refresh()  # 重新整理按鈕browser.close()  # 關閉當前視窗browser.quit()  # 退出瀏覽器

尋找方法

以下列舉常用的尋找Element的方法。

方法名 返回的WebElement
find_element_by_id(id) 匹配id屬性值的元素
find_element_by_name(name) 匹配name屬性值的元素
find_element_by_class_name(name) 匹配CSS的class值的元素
find_element_by_tag_name(tag) 匹配標籤名的元素,如div
find_element_by_css_selector(selector) 匹配CSS選取器
find_element_by_xpath(xpath) 匹配xpath
find_element_by_link_text(text) 完全符合提供的text的a標籤
find_element_by_partial_link_text(text) 提供的text可以是a標籤中文本中的一部分

登入CSDN

以下代碼可以類比輸入帳號密碼,點擊登入。整個過程還是很快的。

browser = webdriver.Chrome()browser.get('https://passport.csdn.net/account/login')browser.find_element_by_id('username').send_keys('haiyu19931121@163.com')browser.find_element_by_id('password').send_keys('**********')browser.find_element_by_class_name('logging').click()

以上差不多都是API的羅列,其中有自己的理解,也有照搬官方文檔的。

by @sunhaiyu

2017.7.13

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.