Python函式單元測試以及爬蟲的基本實現
一.Python程式函式的測試
Python中有一個自帶的單元測試框架是unittest模組,用它來做單元測試,它裡面封裝好了一些校驗返回的結果方法和一些用例執行前的初始化操作。
在說unittest之前,先說幾個概念:
TestCase 也就是測試用例
TestSuite 多個測試用例集合在一起,就是TestSuite
TestLoader是用來載入TestCase到TestSuite中的
TestRunner是來執行測試用例的,測試的結果會儲存到TestResult例項中,包括運行了多少測試用例,成功了多少,失敗了多少等資訊
接下來我們就選出一部分程式碼來進行一個簡單的測試
這是一個簡單的比賽結束函式,下面我們來測試它是否可用
def gameOver(a,b): if a>=10 and b>=10: if abs(a-b)==2: return True if a<10 or b<10: if a==11 or b==11: return True else: return False
首先我們編寫一個
Game.py
class Game(): def __init__(self,a,b): self.a = a self.b = b
再編寫一個測試程式碼
Testgame.py
import unittest from game import Game class GameTest(unittest.TestCase): #一個測試用例 def test_gameOver(self): self = Game('15','13') #要測試的函式 def gameOver(a,b): if a>=10 and b>=10: if abs(a-b)==2: return True if a<10 or b<10: if a==11 or b==11: return True else: return False #執行測試程式碼 unittest.main()
效果如下
完美執行,此函式無問題。
二.requests庫的運用
1.爬蟲的基本框架是獲取HTML頁面資訊,解析頁面資訊,儲存結果,requests模組是用於第一步獲取HTML頁面資訊; requests庫用於爬取HTML頁面,提交網路請求,基於urllib,但比urllib更方便。
2.安裝requests庫
開啟命令列,輸入
pip install requests
即可安裝
3.下面介紹一些requests庫的基本用法
get方法,它能夠獲得url的請求,並返回一個response物件作為響應。
常見的HTTP狀態碼:200 - 請求成功,301 - 資源(網頁等)被永久轉移到其它URL,404 - 請求的資源(網頁等)不存在,500 - 內部伺服器錯誤。
4.例項
我們現在用requests庫訪問搜狗主頁20次,並獲取一些資訊
import requests for i in range(20): r = requests.get("https://www.sogou.com")#搜狗主頁 print("網頁返回狀態:{}".format(r.status_code)) print("text內容為:{}".format(r.text)) print("\n") print("text內容長度為:{}".format(len(r.text))) print("content內容長度為:{}".format(len(r.content)))
程式碼執行後結果如下
三.BeautifulSoup庫的運用
安裝方式:
開啟命令列,輸入
pip install BeautifulSoup4
1.簡介
beautifulsoup是一個非常強大的工具,爬蟲利器。
beautifulSoup “美味的湯,綠色的濃湯”
一個靈活又方便的網頁解析庫,處理高效,支援多種解析器。
利用它就不用編寫正則表示式也能方便的實現網頁資訊的抓取。
2.常用解析庫
Beautiful Soup支援Python標準庫中的HTML解析器,還支援一些第三方的解析器,
如果我們不安裝它,則 Python 會使用 Python預設的解析器,lxml 解析器更加強大,速度更快,推薦安裝。
3.基本使用
# BeautifulSoup入門 from bs4 import BeautifulSoup html = ''' <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> ''' soup = BeautifulSoup(html,'lxml') # 建立BeautifulSoup物件 print(soup.prettify()) # 格式化輸出 print(soup.title) # 列印標籤中的所有內容 print(soup.title.name) # 獲取標籤物件的名字 print(soup.title.string) # 獲取標籤中的文字內容 == soup.title.text print(soup.title.parent.name) # 獲取父級標籤的名字 print(soup.p) # 獲取第一個p標籤的內容 print(soup.p["class"]) # 獲取第一個p標籤的class屬性 print(soup.a) # 獲取第一個a標籤 print(soup.find_all('a')) # 獲取所有的a標籤 print(soup.find(id='link3')) # 獲取id為link3的標籤 print(soup.p.attrs) # 獲取第一個p標籤的所有屬性 print(soup.p.attrs['class']) # 獲取第一個p標籤的class屬性 print(soup.find_all('p',class_='title')) # 查詢屬性為title的p # 通過下面程式碼可以分別獲取所有的連結以及文字內容 for link in soup.find_all('a'): print(link.get('href')) # 獲取連結 print(soup.get_text())獲取文字
(1):標籤選擇器
在快速使用中我們新增如下程式碼:
print(soup.title)
print(type(soup.title))
print(soup.head)
print(soup.p)
通過這種soup.標籤名 我們就可以獲得這個標籤的內容
這裡有個問題需要注意,通過這種方式獲取標籤,如果文件中有多個這樣的標籤,返回的結果是第一個標籤的內容,如我們通過soup.p獲取p標籤,而文件中有多個p標籤,但是隻返回了第一個p標籤內容。
(2):獲取名稱
當我們通過soup.title.name的時候就可以獲得該title標籤的名稱,即title。
(3):獲取屬性
print(soup.p.attrs['name'])
print(soup.p['name'])
上面兩種方式都可以獲取p標籤的name屬性值
(4):獲取內容
print(soup.p.string)
結果就可以獲取第一個p標籤的內容。
(5):巢狀選擇
我們直接可以通過下面巢狀的方式獲取
print(soup.head.title.string)
(6):標準選擇器
find_all
find_all(name,attrs,recursive,text,**kwargs)
可以根據標籤名,屬性,內容查詢文件
1.name
html=''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </div> <div class="panel-body"> <ul class="list" id="list-1"> <li class="element">Foo</li> <li class="element">Bar</li> <li class="element">Jay</li> </ul> <ul class="list list-small" id="list-2"> <li class="element">Foo</li> <li class="element">Bar</li> </ul> </div> </div> ''' from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.find_all('ul')) # 找到所有ul標籤 print(type(soup.find_all('ul')[0])) # 拿到第一個ul標籤 # find_all可以多次巢狀,如拿到ul中的所有li標籤 for ul in soup.find_all('ul'): print(ul.find_all('li'))
2.attrs
html=''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </div> <div class="panel-body"> <ul class="list" id="list-1" name="elements"> <li class="element">Foo</li> <li class="element">Bar</li> <li class="element">Jay</li> </ul> <ul class="list list-small" id="list-2"> <li class="element">Foo</li> <li class="element">Bar</li> </ul> </div> </div> ''' from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.find_all(attrs={'id': 'list-1'})) # 找到id為ilist-1的標籤 print(soup.find_all(attrs={'name': 'elements'})) # 找到name屬性為elements的標籤
注意:attrs可以傳入字典的方式來查詢標籤,但是這裡有個特殊的就是class,因為class在python中是特殊的欄位,所以如果想要查詢class相關的可以更改attrs={'class_':'element'}或者soup.find_all('',{"class":"element}),特殊的標籤屬性可以不寫attrs,例如id。
例項
程式碼如下
# -*- coding: utf-8 -*- """ Created on Mon May 20 19:33:22 2019 @author: moyulin """ import re from bs4 import BeautifulSoup html = """ <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鳥教程(runoob.com)</title> </head> <body> <h1>我的第一個標題</h1> <p id="first">我的第一個段落。</p> <table border="1"> <tr> <td>row 1, cell 1<\td> <td>row 1, cdll 2<\td> <\tr> <tr> <td>row 2, cell 1<\td> <td>row 2, cell 2<\td> <\tr> <\table> <\body> <\html> """ soup = BeautifulSoup(html,"html.parser") print(soup.prettify()) print("(A).該html的head標籤內容為\n{}\n03".format(soup.head.prettify())) print("\n") print("(B).該html的body標籤內容為\n{}".format(soup.body.prettify())) print("(C).該html中id為first的標籤物件為:{}".format(soup.find(id="first"))) print("(D).該html中所有的中文字元為:{}".format(soup.find_all(string = re.compile('[^\x00-\xff]'))))#這裡用到正則表示式來找出中文字串
執行結果為
&n