初識python及數(shù)據(jù)爬取

初識python

作為一位前端開發(fā)人員,一直以來,接觸最多的也都是html,css,js;有時候會需要搭建一些node服務(wù)器,寫一些node后臺代碼,僅此而已;

而python,只是在以前使用某些軟件時,需要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ǔ)的教程,我覺得非常適合我這種從來沒有接觸過的人;隨后,我花了幾個小時的時間,將這里面基礎(chǔ)教程的所有內(nèi)容看了一遍,在看的過程中,也跟著做了一些練習(xí);

雖然說,看了基礎(chǔ)教程,也頂多你大概能夠使用python進(jìn)行一些簡單的運(yùn)算而已;而作為開發(fā)人員,都明白一個道理,最好、最快的學(xué)習(xí)一種語言的方式當(dāng)然是從一個簡單的項(xiàng)目開始,自己能夠從頭開始做一個自己覺得有意思但是難度不是很大的東西,這樣,不僅能夠讓自己能夠更快的去理解這種語言,而且,會使自己更有學(xué)習(xí)的動力和信心;因此,我開始了一個簡單的網(wǎng)站的數(shù)據(jù)爬取的實(shí)現(xiàn),因?yàn)閷τ谖疫@種前端出生的人來說,與瀏覽器打交道,與網(wǎng)頁打交道,相對來說,簡單很多;

開始

首先,我肯定不知道從何處開始,因此,我只能繼續(xù)百度“python 爬蟲”;最后找到了這篇文章“Python爬蟲實(shí)戰(zhàn)二之爬取百度貼吧帖子”,為什么選擇它呢?只有一個原因,在它的文章最后,有完整的代碼,我沒去看里面的描述,而是,直接用sublime直接創(chuàng)建了一個名為

$ pachong.py

的文件,然后將代碼全部拷貝進(jìn)去(雖然說可能代碼根本運(yùn)行不通);

隨后,我開始了我的爬蟲之旅,一開始,我就直接在拷貝的代碼基礎(chǔ)上直接修改,而不同的是它爬取的是百度貼吧,我爬取的是汽車之家。然后代碼就在這兒pachong.py(由于代碼較多,就不直接貼出來了,有興趣的,可以直接點(diǎn)鏈接進(jìn)github查看);在這里面有個很坑的地方,它的所有篩選自己需要數(shù)據(jù)的方式是通過正則匹配的方式實(shí)現(xiàn)的,而我什么也不知道的跟著學(xué)著,也使用正則,讓我為了從整個html中篩選自己需要的,花費(fèi)了太多的時間,而且效果一般;但是后面才發(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é),可以看下這個感覺挺全的;

以爬取螞蜂窩的游記為例,比如這一篇

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、獲取用戶信息(如頭像,名稱),這個稍微要復(fù)雜一些,因?yàn)樗谏厦娴谝徊街苯诱埱蟮膆tml頁面里面是找不到的,然后通過Chrome DevTools中的Network功能,可以找到拉取這些信息的請求地址“https://www.mafengwo.cn/note/pagelet/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249”,細(xì)心的你可能會發(fā)現(xiàn),在這個請求中有個“6958115”,這個不就是第一步里面頁面的結(jié)尾數(shù)字嗎,我們可以理解為id;那么,這個請求就是通過

開始

https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249](https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%7B%22iid%22%3A%22

加上 id

6958115

加上結(jié)尾

%22%7D&_=1492868086249

最后組合成的一個完整的url,然后通過第一步請求后,將獲取的數(shù)據(jù)通過正則的方式,只去html部分,然后通過BeautifulSoup取出對應(yīng)的頭像,姓名;

//其中article_id就是上面說的第一步鏈接結(jié)尾數(shù)字“6958115”
userInfoURL = 'https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919&params=%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搭建一個簡單的本地服務(wù)器;因?yàn)橥ㄟ^學(xué)習(xí)python的時候發(fā)現(xiàn)菜鳥教程確實(shí)比較適合我這種菜鳥的,所以就看完了Django 菜鳥教程,這個教程雖然簡單,但是全面,對我做一個簡單服務(wù)器來說,足夠了;然后,就通過這個教程搭建了一個簡單的python服務(wù)器,在瀏覽器中,就可以看到自己爬取的頁面了,具體可見整個項(xiàng)目代碼

mongodb 數(shù)據(jù)保存、使用

在你爬取一篇過后,肯定是不會停止的,所以,我們總會找個能夠保持我們爬取數(shù)據(jù)的地方(數(shù)據(jù)庫);因?yàn)橐郧霸谶M(jìn)行node開發(fā)的時候,使用過mongodb,所以就選擇了它作為我保存數(shù)據(jù)的地方;使用python來操作mongodb,我沒有找到相關(guān)比較好的文章,所以就直接參考的PyMongo 3.4.0 documentation這個api文檔,這個夜比較詳細(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ù)保存的代碼就不貼出來了,有興趣可以看這個models.py.

自動爬取所有游記

當(dāng)你想爬取更多的時候,你肯定不希望是自己手動去查找一個一個的id,然后手動爬取,所以,我們就希望有更加自動化的爬取方式;對于這種方式,必須得解決下面兩個問題:

  • 獲取所有的游記id(就形如“6958115”這種的東西)
  • 解決因?yàn)樽詣踊埱筮^快,過于頻繁,導(dǎo)致“服務(wù)器拒絕訪問”的問題

第一個,獲取所有id;當(dāng)你使用Chrome DevTools Network去看列表下一頁的請求的時候,你會發(fā)現(xiàn),它訪問了一個“http://www.mafengwo.cn/note/pagelet/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522&params=%7B%22type%22%3A0%2C%22objid%22%3A0%2C%22page%22%3A1%2C%22ajax%22%3A1%2C%22retina%22%3A0%7D&_=1492999206862”這樣的鏈接,它也是和上面獲取用戶信息一樣分成三個部分,其中有個第幾頁的參數(shù)“page=1”,這里面就返回了所有的列表的html代碼,其中包括我們需要的id;

url = 'http://www.mafengwo.cn/note/__pagelet__/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522&params=%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ù),直到最后一頁

只是在跑的過程中,就會遇到第二個問題,因?yàn)樵L問過快、過于頻繁而導(dǎo)致服務(wù)器拒絕訪問,在這兒我沒有通過網(wǎng)上說的各種高端的方式,而是采用的比較笨重的方式,就是在跑完一個請求后,讓程序休息幾秒鐘,再去進(jìn)行下一個請求,我將時間設(shè)置的10秒,目前沒有拒絕訪問的問題,只是跑起來比較慢一些;

import time

.....
time.sleep(10)
.....

對于上面的所有代碼,如果感興趣的,整個項(xiàng)目代碼可以在這兒(github)找到.

目前,爬取就差不多只有這些,后面會慢慢繼續(xù)去完善和學(xué)習(xí);對于我來說,python的學(xué)習(xí)之路也才剛剛開始;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,062評論 25 709
  • 聲明:本文講解的實(shí)戰(zhàn)內(nèi)容,均僅用于學(xué)習(xí)交流,請勿用于任何商業(yè)用途! 一、前言 強(qiáng)烈建議:請在電腦的陪同下,閱讀本文...
    Bruce_Szh閱讀 13,009評論 6 28
  • 我叔叔來信了,說是找我借錢? 他這么有錢,一個大商人,都快進(jìn)福布斯排行榜的人,找我借錢?難道是破產(chǎn)了? 他說的很明...
    予墨讀書閱讀 133評論 0 0
  • 走出一身汗 回家 越來越喜歡流汗的感覺 朋友小聚完 繼續(xù)走壩 此時 沒有什么人 除了一兩對黑暗中緊擁的情侶 除了一...
    撞墻的豆腐閱讀 452評論 0 0
  • 那一潭洶涌的真心實(shí)意, 在念念不忘中丟了執(zhí)著, 曾經(jīng)相融進(jìn)生命的風(fēng)景, 在人來人往中淡了視線, 捧起的流沙散落了,...
    蛋蛋妮兒閱讀 448評論 0 0

友情鏈接更多精彩內(nèi)容