初識python
作為一位前端開發(fā)人員访递,一直以來,接觸最多的也都是html同辣,css拷姿,js;有時(shí)候會需要搭建一些node服務(wù)器邑闺,寫一些node后臺代碼跌前,僅此而已;
而python陡舅,只是在以前使用某些軟件時(shí)抵乓,需要python環(huán)境,就安裝到了電腦,然后灾炭,從來都沒有真正的接觸過它茎芋;
隨著數(shù)據(jù)分析、深度學(xué)習(xí)蜈出、機(jī)器學(xué)習(xí)的發(fā)展田弥,也讓我開始了python的學(xué)習(xí)之旅;雖然都說铡原,不管是什么語言偷厦,基本上都是相通的;但是對于一種你從未接觸過的語言燕刻,基礎(chǔ)只泼,還是非常重要的;所以卵洗,我還是默默的打開了瀏覽器请唱,在百度中搜索了“python基礎(chǔ)教程”,最后找到了Python 基礎(chǔ)教程 | 菜鳥教程过蹂,在這里面十绑,有環(huán)境的搭建、基本語法酷勺、數(shù)據(jù)類型本橙、常用函數(shù)等非常基礎(chǔ)的教程鸥印,我覺得非常適合我這種從來沒有接觸過的人勋功;隨后,我花了幾個(gè)小時(shí)的時(shí)間库说,將這里面基礎(chǔ)教程的所有內(nèi)容看了一遍狂鞋,在看的過程中,也跟著做了一些練習(xí)潜的;
雖然說骚揍,看了基礎(chǔ)教程,也頂多你大概能夠使用python進(jìn)行一些簡單的運(yùn)算而已啰挪;而作為開發(fā)人員信不,都明白一個(gè)道理,最好亡呵、最快的學(xué)習(xí)一種語言的方式當(dāng)然是從一個(gè)簡單的項(xiàng)目開始抽活,自己能夠從頭開始做一個(gè)自己覺得有意思但是難度不是很大的東西,這樣锰什,不僅能夠讓自己能夠更快的去理解這種語言下硕,而且丁逝,會使自己更有學(xué)習(xí)的動力和信心;因此梭姓,我開始了一個(gè)簡單的網(wǎng)站的數(shù)據(jù)爬取的實(shí)現(xiàn)霜幼,因?yàn)閷τ谖疫@種前端出生的人來說,與瀏覽器打交道誉尖,與網(wǎng)頁打交道罪既,相對來說,簡單很多铡恕;
開始
首先琢感,我肯定不知道從何處開始,因此探熔,我只能繼續(xù)百度“python 爬蟲”猩谊;最后找到了這篇文章“Python爬蟲實(shí)戰(zhàn)二之爬取百度貼吧帖子”,為什么選擇它呢?只有一個(gè)原因祭刚,在它的文章最后,有完整的代碼墙牌,我沒去看里面的描述涡驮,而是,直接用sublime直接創(chuàng)建了一個(gè)名為
$ pachong.py
的文件喜滨,然后將代碼全部拷貝進(jìn)去(雖然說可能代碼根本運(yùn)行不通)捉捅;
隨后,我開始了我的爬蟲之旅虽风,一開始棒口,我就直接在拷貝的代碼基礎(chǔ)上直接修改,而不同的是它爬取的是百度貼吧辜膝,我爬取的是汽車之家无牵。然后代碼就在這兒pachong.py(由于代碼較多,就不直接貼出來了厂抖,有興趣的茎毁,可以直接點(diǎn)鏈接進(jìn)github查看);在這里面有個(gè)很坑的地方忱辅,它的所有篩選自己需要數(shù)據(jù)的方式是通過正則匹配的方式實(shí)現(xiàn)的七蜘,而我什么也不知道的跟著學(xué)著,也使用正則墙懂,讓我為了從整個(gè)html中篩選自己需要的橡卤,花費(fèi)了太多的時(shí)間,而且效果一般损搬;但是后面才發(fā)現(xiàn)碧库,已經(jīng)有很完善的專門匹配頁面內(nèi)容方式的Python庫BeautifulSoup(這是它的中文文檔鏈接)柜与;
使用BeautifulSoup重寫
當(dāng)發(fā)現(xiàn)了BeautifulSoup之后,簡單看了一篇BeautifulSoup教程谈为,看完之后旅挤,如獲至寶,因?yàn)樗氖褂梅绞嚼锩嬗泻芏嗪颓岸死锩嫒カ@取元素伞鲫,獲取節(jié)點(diǎn)有異曲同工之妙粘茄;而我最喜歡使用的,是里面的“CSS選擇器”方式秕脓,簡直和前端使用jquery一模一樣柒瓣,比如:
通過標(biāo)簽名查找
print soup.select('p')
通過類名查找
print soup.select('.sister')
通過 id 名查找
print soup.select('#link1')
......等等;
因此吠架,我果斷選擇使用BeautifulSoup對上面最初的版本進(jìn)行重寫芙贫,尤其是在對內(nèi)容的篩選;而這一次傍药,我選擇了去爬取“螞蜂窩”的游記磺平;
作為前端開發(fā)的我,對于Chrome DevTools的使用拐辽,簡直是易如反掌拣挪;所以很容易就可以找出怎么去獲取自己需要的內(nèi)容(到底是用類名查找還是id查找,或者是什么組合查找)俱诸,對于Chrome DevTools不是很熟的同學(xué)菠劝,可以看下這個(gè)感覺挺全的;
以爬取螞蜂窩的游記為例睁搭,比如這一篇:
1赶诊、通過request獲取網(wǎng)頁
request = urllib2.Request('http://www.mafengwo.cn/i/6958115.html')
response = urllib2.urlopen(request)
soup = BeautifulSoup(response.read().decode('utf8').encode('utf8'), "html.parser")
2、獲取標(biāo)題
return soup.select('.headtext')[0].string
3园骆、獲取文章html內(nèi)容
article = soup.select('.vc_article')[0]
html = article.prettify()
4舔痪、獲取用戶信息(如頭像,名稱),這個(gè)稍微要復(fù)雜一些锌唾,因?yàn)樗谏厦娴谝徊街苯诱埱蟮膆tml頁面里面是找不到的辙喂,然后通過Chrome DevTools中的Network功能,可以找到拉取這些信息的請求地址“https://www.mafengwo.cn/note/pagelet/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249”鸠珠,細(xì)心的你可能會發(fā)現(xiàn)巍耗,在這個(gè)請求中有個(gè)“6958115”,這個(gè)不就是第一步里面頁面的結(jié)尾數(shù)字嗎渐排,我們可以理解為id炬太;那么,這個(gè)請求就是通過
開始
https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249](https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%22
加上 id
6958115
加上結(jié)尾
%22%7D&_=1492868086249
最后組合成的一個(gè)完整的url驯耻,然后通過第一步請求后亲族,將獲取的數(shù)據(jù)通過正則的方式炒考,只去html部分,然后通過BeautifulSoup取出對應(yīng)的頭像霎迫,姓名斋枢;
//其中article_id就是上面說的第一步鏈接結(jié)尾數(shù)字“6958115”
userInfoURL = 'https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%22' + article_id +'%22%7D&_=1492868086249'
request = urllib2.Request(userInfoURL)
response = urllib2.urlopen(request)
result = response.read()
pattern = re.compile('jQuery.*?\(')
pattern1 = re.compile('\)\;')
result = re.sub(pattern, "", result)
result = re.sub(pattern1, "", result)
result = eval(result)
html = result['data']['html']
soup = BeautifulSoup(html, "html.parser")
//頭像
avatar = soup.select('.per_pic img')[0]['src']
//用戶名
name = soup.select('.per_name')[0]['title'].encode('utf-8')
搭建服務(wù)器
在你爬取到數(shù)據(jù)之后,你總會希望能夠在界面上能夠真正的展示出來知给,所以瓤帚,我就決定使用python搭建一個(gè)簡單的本地服務(wù)器;因?yàn)橥ㄟ^學(xué)習(xí)python的時(shí)候發(fā)現(xiàn)菜鳥教程確實(shí)比較適合我這種菜鳥的涩赢,所以就看完了Django 菜鳥教程戈次,這個(gè)教程雖然簡單,但是全面筒扒,對我做一個(gè)簡單服務(wù)器來說怯邪,足夠了;然后花墩,就通過這個(gè)教程搭建了一個(gè)簡單的python服務(wù)器悬秉,在瀏覽器中,就可以看到自己爬取的頁面了冰蘑,具體可見整個(gè)項(xiàng)目代碼
mongodb 數(shù)據(jù)保存搂捧、使用
在你爬取一篇過后,肯定是不會停止的懂缕,所以,我們總會找個(gè)能夠保持我們爬取數(shù)據(jù)的地方(數(shù)據(jù)庫)王凑;因?yàn)橐郧霸谶M(jìn)行node開發(fā)的時(shí)候搪柑,使用過mongodb,所以就選擇了它作為我保存數(shù)據(jù)的地方索烹;使用python來操作mongodb工碾,我沒有找到相關(guān)比較好的文章,所以就直接參考的PyMongo 3.4.0 documentation這個(gè)api文檔百姓,這個(gè)夜比較詳細(xì)和簡單渊额,對于我來說夠用了;它包含了如何和mongodb鏈接垒拢、如何獲取數(shù)據(jù)庫旬迹,如何獲取數(shù)據(jù)庫里面的collection,如何查找求类、添加數(shù)據(jù)等等奔垦;其實(shí)很簡單:
from pymongo import MongoClient
import settings
#連接mongodb
client=MongoClient('mongodb://127.0.0.1:27017/')
//獲取數(shù)據(jù)庫
db = client[settings.DBNAME]
// 獲取數(shù)據(jù)庫里面的collection
def getCollection(collection):
if(collection):
return db[collection]
else:
return None
數(shù)據(jù)保存的代碼就不貼出來了,有興趣可以看這個(gè)models.py.
自動爬取所有游記
當(dāng)你想爬取更多的時(shí)候尸疆,你肯定不希望是自己手動去查找一個(gè)一個(gè)的id椿猎,然后手動爬取惶岭,所以,我們就希望有更加自動化的爬取方式犯眠;對于這種方式按灶,必須得解決下面兩個(gè)問題:
- 獲取所有的游記id(就形如“6958115”這種的東西)
- 解決因?yàn)樽詣踊埱筮^快,過于頻繁筐咧,導(dǎo)致“服務(wù)器拒絕訪問”的問題
第一個(gè)鸯旁,獲取所有id;當(dāng)你使用Chrome DevTools Network去看列表下一頁的請求的時(shí)候嗜浮,你會發(fā)現(xiàn)羡亩,它訪問了一個(gè)“http://www.mafengwo.cn/note/pagelet/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522¶ms=%7B%22type%22%3A0%2C%22objid%22%3A0%2C%22page%22%3A1%2C%22ajax%22%3A1%2C%22retina%22%3A0%7D&_=1492999206862”這樣的鏈接,它也是和上面獲取用戶信息一樣分成三個(gè)部分危融,其中有個(gè)第幾頁的參數(shù)“page=1”,這里面就返回了所有的列表的html代碼畏铆,其中包括我們需要的id;
url = 'http://www.mafengwo.cn/note/__pagelet__/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522¶ms=%7B%22type%22%3A0%2C%22objid%22%3A0%2C%22page%22%3A'+str(page)+'%2C%22ajax%22%3A1%2C%22retina%22%3A0%7D&_=1492999206862'
request = urllib2.Request(url)
response = urllib2.urlopen(request)
result = response.read()
pattern = re.compile('jQuery.*?\(')
pattern1 = re.compile('\)\;')
result = re.sub(pattern, "", result)
result = re.sub(pattern1, "", result)
result = eval(result)
html = result['data']['html']
html = html.replace('\\/', '/')
html = html.decode('string-escape')
soup = BeautifulSoup(html, "html.parser")
links = soup.select('.tn-item .tn-image a')
_ids = []
for link in links:
_id = link['href'].replace('/i/', '').replace('.html', '')
_ids.append(_id)
然后我們就會根據(jù)每一頁獲取的id循環(huán)自動跑爬取對應(yīng)頁面數(shù)據(jù)并保存至數(shù)據(jù)庫吉殃,每跑完一頁的數(shù)據(jù)辞居,就會遞歸跑下一頁數(shù)據(jù),直到最后一頁
只是在跑的過程中蛋勺,就會遇到第二個(gè)問題瓦灶,因?yàn)樵L問過快、過于頻繁而導(dǎo)致服務(wù)器拒絕訪問抱完,在這兒我沒有通過網(wǎng)上說的各種高端的方式贼陶,而是采用的比較笨重的方式,就是在跑完一個(gè)請求后巧娱,讓程序休息幾秒鐘碉怔,再去進(jìn)行下一個(gè)請求,我將時(shí)間設(shè)置的10秒禁添,目前沒有拒絕訪問的問題撮胧,只是跑起來比較慢一些;
import time
.....
time.sleep(10)
.....
對于上面的所有代碼老翘,如果感興趣的芹啥,整個(gè)項(xiàng)目代碼可以在這兒(github)找到.
目前,爬取就差不多只有這些铺峭,后面會慢慢繼續(xù)去完善和學(xué)習(xí)潮剪;對于我來說敷硅,python的學(xué)習(xí)之路也才剛剛開始;