介紹
一直想有時間學(xué)習(xí)爬蟲技術(shù)撒汉,現(xiàn)在來吧,跟著OReilly 出版的Web Scraping with Python 這本書來學(xué)習(xí)。
環(huán)境準(zhǔn)備
因為本書推薦Python3為例,去官網(wǎng)下載Python3.x版本的Python安裝包试吁,直接安裝就好了。安裝的時候注意勾選加入path楼咳。
話說我還沒有學(xué)Python呢親( ⊙ o ⊙ )熄捍!,沒關(guān)系先稀里糊涂的用吧~~~ 不行了再說
第一只爬蟲
書中首先做了一些介紹爬橡,主要內(nèi)容是網(wǎng)絡(luò)傳輸?shù)倪^程治唤,說白了就是web交互其實可以跟瀏覽器沒有啥關(guān)系,而爬蟲就是不通過瀏覽器從服務(wù)端去爬數(shù)據(jù)...
初見
ok閑言碎語不要講來寫爬蟲吧
新建一個文件夾糙申,里面建一個test.py文件宾添,在里面寫入:
from urllib.request import urlopen
html = urlopen("http://pythonscraping.com/pages/page1.html")
print(html.read())
據(jù)說Python是一個很矯情的對空格、縮進敏感的語言..所以一定要注意不要亂打空格和縮進
保存柜裸,然后命令行cd到這個文件的目錄:
phython test.py
可以看到打印出來的html
美麗的湯
BeautifulSoup是一個lib缕陕,用來更好的解析html和xml的。
安裝湯
python3自帶了pip所以可以直接用pip安裝
pip install beautifulsoup4
Virtual Environments是一個隔離各個項目lib防止沖突的機制疙挺,由于我初學(xué)扛邑,先不用
安裝完bs4之后試一下:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/page1.html")
bsObj = BeautifulSoup(html.read())
print(bsObj.h1)
直接使用bsObj.h1找到了html中的h1標(biāo)簽里的內(nèi)容。這是比較暴力的寫法铐然,比較精確的寫法是bsObj.html.body.h1
異常處理
異常處理可以使程序更健壯蔬崩,不容易直接掛掉〔笫睿看下面的寫法:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
def getTitle(url):
try:
html = urlopen(url)
except HTTPError as e:
return None
try:
bsObj = BeautifulSoup(html.read())
title = bsObj.body.h1
except AttributeError as e:
return None
return title
title = getTitle("http://www.pythonscraping.com/pages/page1.html")
if title == None:
print("Title could not be found")
else:
print(title)
以上方法才是比較正規(guī)健壯的寫法沥阳,一定要注意格式,不然會報錯的自点,不行就裝個IDE 比如Pycharm桐罕,如果格式不正確會有提示。
高級HTML解析
從一個復(fù)雜的頁面提取到需要的信息可能需要深層的抓取比如:
bsObj.findAll("table")[4].findAll("tr")[2].find("td").findAll("div")[1].find("a")
這樣的代碼很可怕也很脆弱,當(dāng)頁面出現(xiàn)改動后功炮,這個路徑就抓不到信息了溅潜。
有什么解決方案?
- 通過手機版或打印預(yù)覽薪伏,來獲取更規(guī)范的HTML
- 解析網(wǎng)頁引用的js文件
- 通過網(wǎng)頁URL獲取信息
- 從其他類似的網(wǎng)站獲取信息
書上說的以上方法很濕滚澜,一點都不干貨...
BeautifulSoup 的其功能
使用屬性、導(dǎo)航樹嫁怀、搜索標(biāo)簽
網(wǎng)頁的樣式表 也可以用來查找信息
看例子博秫,這個網(wǎng)頁,有red和green的文字:
http://www.pythonscraping.com/pages/warandpeace.html
下面我們來爬一下眶掌,打印出所有綠色的文字:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/warandpeace.html")
bsObj = BeautifulSoup(html)
nameList = bsObj.findAll("span", {"class":"green"})
for name in nameList:
print(name.get_text())
以上,使用bsObj.findAll(tagName, tagAttributes)查詢返回列表
find()和findAll()的用法
findAll(tag, attributes, recursive, text, limit, keywords)
find(tag, attributes, recursive, text, keywords)
查找多個類型的標(biāo)題:
.findAll({"h1","h2","h3","h4","h5","h6"})
查找多個屬性:
.findAll("span", {"class":"green", "class":"red"})
遞歸
findAll()方法的遞歸屬性默認(rèn)是true巴碗,意味著查找所有子節(jié)點朴爬。
以內(nèi)容為條件查詢標(biāo)簽:
nameList = bsObj.findAll(text="the prince")
print(len(nameList))
limit
limit是限制查找的個數(shù),比如只返回前10個符合條件的標(biāo)簽
keywords
有點復(fù)雜 先不看
Navigation Trees
Navigation Tree就類似這種用法:
bsObj.tag.subTag.anotherSubTag
一個用來做例子的頁面:
http://www.pythonscraping.com/pages/page3.html
處理子節(jié)點和后代節(jié)點
在BeautifulSoup里面 子節(jié)點child和“”孫子及后代“descendants 是被兩個概念橡淆。兩個范圍沒有交集召噩。
注意bsObj.body.h1這個代碼返回的不一定是 body-h1,而有可能是body-........h1。
如果只想得到兒子則使用:bsObj.find("table",{"id":"giftList"}).children這種方式逸爵。
處理sibling兄弟姐妹
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
for sibling in bsObj.find("table",{"id":"giftList"}).tr.next_siblings:
print(sibling)
打印出了所有的產(chǎn)品內(nèi)容具滴,出了第一行title。原因:
- sibling(兄弟)不包括自己
- next_siblings只返回next的师倔,而不是它和它之前的构韵,如果object本身在在隊列中間,那么只返回它后面的兄弟
同理如果需要返回前面的兄弟可以使用previous_siblings
以上兩周可以理解為趋艘,返回哥哥疲恢、返回弟弟
另外,去掉siblings后面的s 可以只返回一個靠的最近的兄弟瓷胧。
處理爹媽,父標(biāo)簽(這標(biāo)題...)
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
print(bsObj.find("img",{"src":"../img/gifts/img1.jpg"}).parent.previous_sibling.get_text())
正則表達
正則表達式....呃 頭大
As the old computer-science joke goes: “Let’s say you have a problem, and you decide
to solve it with regular expressions. Well, now you have two problems.”
爬蟲技術(shù)脫不了使用正則表達式
上面的例子使用的是準(zhǔn)確的src來找到特指的img显拳,但是如果要找很多的img就要使用正則了:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
images = bsObj.findAll("img", {"src":re.compile("\.\.\/img\/gifts/img.*\.jpg")})
for image in images:
print(image["src"])
獲取屬性
myImgTag.attrs['src']
Lambda表達式
將一個方法作為變量傳遞到另一個方法中,但是方法的參數(shù)必須是一個tag返回一個boolean
例子:
soup.findAll(lambda tag: len(tag.attrs) == 2)
返回有兩個屬性的標(biāo)簽
這可能是替代正則表達式的一種方法