爬蟲基礎
1.urllib.request模塊html
urlopen():打開一個給定URL字符串表示的Web鏈接,並返回文件了類型的對象
urlopen()對象的最經常使用方法:
f.read():讀取全部字節python
例子:
from urllib.request import urlopen
html = urlopen("http://pythonscraping.com/pages/page1.html")
print(html.read())
print(html.read().decode('utf-8'))git
2.Python bs4模塊:解析HTML
bs4:BeautifulSoup正則表達式
from bs4 import BeautifulSoup
from urllib.request import urlopen
html = urlopen("http://pythonscraping.com/pages/page1.html")
bsObj = BeautifulSoup(html.read(),"lxml")express
注意:bs4解析HTML標籤是沒有層級順序的,如下幾種均可行,可是推薦第二種把層級標籤所有列出來
print(bsObj.h1)
print(bsObj.html.body.h1) (推薦)
print(bsObj.body.h1)
print(bsObj.html.h1)編程
鏈接的穩定性和三種常見異常
、api
1 from urllib.request import urlopen 2 from urllib.error import HTTPError 3 from urllib.error import URLError 4 from bs4 import BeautifulSoup 5 6 def getTitle(url): 7 try: 8 html = urlopen(url) 9 except HTTPError as e: 10 ''' 11 HTTPError:服務器端沒有找到該頁面, 12 或者提取頁面時候發生錯誤 13 ''' 14 print(e) 15 return None 16 except URLError as e: 17 ''' 18 URLError:服務器沒找到,遠程的服務器 19 負責返回HTTP狀態編碼 20 ''' 21 print(e) 22 return None 23 24 try: 25 bsObj = BeautifulSoup(html.read(),"lxml") 26 title = bsObj.body.h1 27 except AttributeError as e: 28 ''' 29 AttributeError:屬性錯誤,試圖得到一個 30 HTML標籤,可是該標籤並不存在,BS返回 31 一個空對象,並拋出該異常 32 33 ''' 34 return None 35 36 return title 37 38 title = getTitle( 39 "http://pythonscraping.com/pages/page1.html") 40 41 if title == None: 42 print("Title could not be found") 43 else: 44 print(title)
HTML解析
from bs4 import BeautifulSoup
bsObj = BeautifulSoup('<b id="tag1" class="boldest"> Extremely bold</b>','lxml')服務器
bsObj的幾個屬性
#返回值:
<html><body><b class="boldest" id="tag1"> Extremely bold</b></body></html>函數
bsObj.name #[document] 文件
bsObj.contents #內容:完整的HTML內容
bsObj.contents[0].name #是一級標題「HTML」測試
bsObj.body
返回值:
<body><b class="boldest" id="tag1"> Extremely bold</b></body>
bsObj.body.contents
返回值:
[<b class="boldest" id="tag1"> Extremely bold</b>]
bsObj.b
bsObj.b.contents
bsObj.string #提取文本信息
bsObj的方法
<html><body><b class="boldest" id="tag1"> Extremely bold</b></body></html>
bsObj.find('b')
bsObj.find('b',id='tag1')
如下兩種寫法均可以
bsObj.find(id='tag1')
bsObj.find('',{'id': 'tag1'})
bsObj.get_text() #做用等同於bsObj.string
#每一個標籤都有本身的name和attrs
bsObj.b.name
bsObj.b.attrs
bsObj.b['id']
bsObj.b.attrs['id']
find()和findAll()
findAll(tag,attributes,recursive,text,limit,keywords)返回一個列表
find(tag,attributes,recursive,text,keywords)返回一個bsObj
tag:HTML標籤,在<>裏面的
attributes:屬性,好比<b id="tag2">xxx</b>中的id
recursive:遞歸,是一個布爾型,True表示findAll函數還會搜索子節點,以及子節點的子節點
例子:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/warandpeace.html")
bsObj = BeautifulSoup(html.read(),"lxml")
nameList = bsObj.findAll(text="the prince")
print(len(nameList))
aList = bsObj.findAll('span',class='red')
class是python中的保留字,通常推薦用字典的表達方法{'class': 'red'}
aList = bsObj.findAll('span',{'class': 'red'})
正則表達式regular expression: regex
簡介和動機
1.如何經過編程使計算機具備在文本中檢索某種模式的能力
2.爲高級的文本模式匹配、抽取、或文本形式的搜索和替換功能提供基礎
3.是一些由字符和特殊符號組成的字符串,它們描述了模式的重複或表述多個字符,因而正則表達式能按照某種模式匹配一系列有類似特徵的字符串
Python中的re模塊
.點號 用於匹配除了換行符\n之外的任何字符
例子:
f.o 在f和o之間,能夠匹配任意一個字符:fao,f9o,f#o
模版:
prog = re.compile(某個模式)
result = prog.match(字符串)
上述兩行代碼能夠合併爲一行:
m = re.match(某個模式,字符串)
m = re.match('f.o','fao')
經常使用正則表達式
| 用於分割不一樣的regex,表示或者的關係
. 匹配除了換行符\n之外的任何字符
^ 從字符串起始邊界開始匹配
$ 匹配任何以...結尾的字符串
\b 匹配任何單詞邊界 boundary
\B 與\b相反
[ ] 匹配某些特定字符
? 匹配模式出現零次或者一次
\w 匹配一個字母 word
\d 匹配一個數字 digit
+ 匹配一個或多個任何字符
{n} 前面的字符重複了n次
regex模式 匹配的字符串
at | home at、home
.. 任意兩個字符
^From 任何以From做爲起始的字符串
river$ 任何以river做爲結尾的字符串
\bthe\b 僅僅匹配單詞the
b[ui]t 匹配單詞but以及bit
\w{3} \w\w\w
例子:
m = re.match('[cr][23][dp][o2]','c3po')
m = re.match('\w\w\w-\d\d\d','abc-123')
m = re.match('\w\w\w-\d\d\d','abc-xyz')
m = re.match('\w{3}','cccsdf')
思考題:
寫出一個知足此regex的字符串,並用match函數測試
pattern = '\w+@(\w+\.)?\w+\.com'
m = re.match(pattern,'23423@qq.com')
qeru@asdf.cn.com
23423@qq.com
注意:\w匹配a-z,A-Z,0-9,包括下劃線_
記憶:與python中變量的命名規則一致
遍歷文檔樹的子節點
1 from urllib.request import urlopen 2 from bs4 import BeautifulSoup 3 4 html = urlopen( 5 "http://pythonscraping.com/pages/page3.html") 6 7 bsObj = BeautifulSoup(html.read(),'lxml') 8 9 print(bsObj.body.table.prettify()) 10 11 ''' 12 #遍歷文檔樹的子節點 13 for child in bsObj.find("table",{"id":"giftList"} 14 ).children: 15 print(child) 16 17 18 #遍歷文檔樹的子孫節點 19 for child in bsObj.find("table",{"id":"giftList"} 20 ).descendants: 21 print(child) 22 23 24 #遍歷文檔樹兄弟節點 25 for sibling in bsObj.find("table",{"id":"giftList"} 26 ).tr.next_siblings: 27 print(sibling) 28 29 30 ''' 31 32 ''' 33 查找id號爲gift3的tr標籤,打印出它的next_siblings, 34 再打印出它的previous_siblings, 35 再打印出它的children 36 37 for child in bsObj.find("tr",{"id":"gift3"}).children: 38 print(child) 39 40 print("***********************************") 41 #遍歷文檔樹父節點 42 print(bsObj.find("img", 43 {"src":"../img/gifts/img1.jpg"})\ 44 .parent.previous_sibling.get_text()) 45 ''' 46 47 #使用正則表達式遍歷文檔樹 48 ''' 49 使用findAll()把網頁中全部的圖片下載下來,打印出圖片的src 50 ''' 51 import re 52 53 images = bsObj.findAll("img",\ 54 {"src":re.compile(\ 55 "\.\.\/img\/gifts/img.*\.jpg")}) 56 57 58 for image in images: 59 print(image["src"])