一個(gè)不那么典型的Python爬蟲

PYTHON爬蟲入門&視頻網(wǎng)站BILIBILI用戶爬取爬蟲詳解

前言

Python使用版本:2.7

得到數(shù)據(jù)挖掘的課題后,我接觸到了Python,也發(fā)現(xiàn)了在同樣的命題下,使用的工具不同,方法不同味悄,即使是得到了同樣的結(jié)果,耗費(fèi)的人力時(shí)間成本也不盡相同塌鸯。
這引起了我對(duì)典型爬蟲方式的便捷程度(主要是程序員角度)的一點(diǎn)思考侍瑟。

典型?

就目前學(xué)習(xí)到的知識(shí)來(lái)看,不使用Scrapy等爬蟲框架的情況下涨颜,Python爬蟲可以說(shuō)是由以下幾個(gè)功能組合起來(lái)的:

模擬瀏覽器發(fā)送請(qǐng)求(GET/POST)

獲取方式分類

GET方法
范例采用requests擴(kuò)展庫(kù)的get函數(shù)

返回頁(yè)面內(nèi)容:


# -*- coding:utf-8 -*-
import requests

url = 'http://space.bilibili.com/218345/#!/'
response = requests.get(url).content
print response

有時(shí)GET方法也有除網(wǎng)址以外的傳入?yún)?shù):Query String Parameters

# -*- coding:utf-8 -*-
import requests
import datetime, time

def datetimeTrans(d):
    currentMachTime = lambda: int(round(time.time() * 1000))
    return currentMachTime()

url = 'http://search.bilibiili.com/all'

payload = {
    'keyword': 'THE GIRL WITH THE'
}

result = requests.get(url, params = payload).content    #inject query string parameters
print result

POST方法
范例使用requests.post()

POST方法常用于請(qǐng)求模擬登陸费韭,需傳入?yún)?shù)“Form Data”

# -*- coding:utf-8 -*-
import requests
import time, datetime

def datetimeTrans(d):
        currentMachTime = lambda: int(round(time.time() * 1000))
        return currentMachTime()


url = 'http://space.bilibili.com/ajax/member/GetInfo?mid=218345'

headers = {
        #pass
}

payload = {
        'mid': 218345
        '_': datetimeTrans(datetime.datetime.now())
}

print url
response = requests.post(url, headers = headers, data = payload).content   #inject form data
print response

GET&POST對(duì)比

GET相較于POST的優(yōu)勢(shì)
(引用知乎上羅志宇的回答)

- 請(qǐng)求中的URL可以被手動(dòng)輸入
- 請(qǐng)求中的URL可以被存在書簽里,或者歷史里庭瑰,或者快速撥號(hào)里面星持,或者分享給別人。
- 請(qǐng)求中的URL是可以被搜索引擎收錄的弹灭。
- 帶云壓縮的瀏覽器督暂,比如Opera mini/Turbo 2, 只有GET才能在服務(wù)器端被預(yù)取的。
- 請(qǐng)求中的URL可以被緩存穷吮。

POST相較于GET方法的特性

-POST不像GET的URL會(huì)顯示在瀏覽器歷史和WEB服務(wù)器日志中逻翁,相較更為安全
-在準(zhǔn)則中,不可重復(fù)的操作(例如創(chuàng)建條目或修改一條記錄)捡鱼,多是由POST請(qǐng)求完成的八回,因?yàn)镻OST不能被緩存,所以瀏覽器不會(huì)多次遞交驾诈。
(關(guān)于這條我們舉個(gè)小例子缠诅。假如你做了一個(gè)BLOG,并設(shè)計(jì)了一個(gè)URL來(lái)刪除你的BLOG上的所有帖子…那么畫面就會(huì)變得很美:一個(gè)搜索引擎的爬蟲爬過(guò)翘鸭,很快你就知道什么叫不作死就不會(huì)死了。)

可見戳葵,POST的GET的運(yùn)用是需要分場(chǎng)合的就乓。

結(jié)合網(wǎng)頁(yè)實(shí)例判別請(qǐng)求類型

由于項(xiàng)目是關(guān)于視頻網(wǎng)站bilibili的,網(wǎng)頁(yè)實(shí)例也來(lái)自bilibili拱烁。
(使用chrome瀏覽器自帶的檢查工具獲取network信息)

GET(myinfo)
需cookie和傳入?yún)?shù)

myinfo.png

POST(getinfo)
Form Data為機(jī)器時(shí)間與用戶ID

getinfo.png

元素定位及資源篩選

光是獲得了網(wǎng)頁(yè)內(nèi)容生蚁,不加以處理將占用大量的空間。所以在進(jìn)行存儲(chǔ)之前戏自,需要定位信息邦投,進(jìn)行信息的過(guò)濾。
這個(gè)時(shí)候就可以選用Xpath或者BeautifulSoup對(duì)網(wǎng)頁(yè)內(nèi)容(HTML/XML)內(nèi)容進(jìn)行分析擅笔。

Xpath
從dom網(wǎng)址尋找網(wǎng)址信息及標(biāo)題信息

# -*- coding:utf-8 -*-
from lxml import etree

dom = etree.HTML(all_text)  #all_text is a string object
url_list = dom.Xpath('//table[@class="list"]/tr[@class="even" or "odd"]/td/span/a[1]/@href') #find links  (@href)
title = dom.Xpath('//*[@id="content"]/div[3]/h1/text()') #find titles (text())

print title
print url_list

BeautifulSoup
BeatufulSoup實(shí)例可以通過(guò)標(biāo)簽等對(duì)象直接進(jìn)行結(jié)點(diǎn)資料的訪問(wèn)志衣,與數(shù)據(jù)儲(chǔ)存的對(duì)接口非常的好
prettify() 結(jié)構(gòu)簡(jiǎn)明化函數(shù),實(shí)例.標(biāo)簽可直接訪問(wèn)結(jié)點(diǎn)

# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup as Soup

url = 'http://space.bilibili.com/218345/#!/'
response = requests.get(url).content
soup = Soup(response)

print soup.prettify()
print soup.title.string
print soup.a
print soup.h1

數(shù)據(jù)保存

  • 不再贅述文件讀寫保存方式猛们,可查詢官方文檔或中文教程

MySQL數(shù)據(jù)庫(kù)
創(chuàng)建MySQL數(shù)據(jù)庫(kù)念脯,創(chuàng)建對(duì)應(yīng)數(shù)據(jù)的表

(指令在cmd或terminal的mysql界面中輸入)

CRATE TABLE bilibili;
USE bilibili;
CREATE TABLE `test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `mid` varchar(11) DEFAULT NULL,
  `name` varchar(45) DEFAULT NULL,
  `sex` varchar(11) DEFAULT NULL,
  `face` varchar(200) DEFAULT NULL,
  `regtime` varchar(45) DEFAULT NULL,
  `spacesta` int(11) DEFAULT NULL,
  `birthday` varchar(45) DEFAULT NULL,
  `place` varchar(45) DEFAULT NULL,
  `attention` int(11) DEFAULT NULL,
  `sign` varchar(300) DEFAULT NULL,
  `attentions` text,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

多線程爬取

map()使得并行代碼可以快速運(yùn)行,而支持map()函數(shù)并行的庫(kù)有multiprocessing.dummy和multiprocessing弯淘。
其中dummy庫(kù)的多進(jìn)程模塊采用的是線程(在Windows中绿店,進(jìn)行CPU分配是以線程為單位的,一個(gè)進(jìn)程可能由多個(gè)線程組成),這能夠使得數(shù)據(jù)輕松的在這兩個(gè)之間進(jìn)行前進(jìn)和回躍假勿,特別是對(duì)于探索性程序來(lái)說(shuō)十分有用借嗽。

# -*- coding:utf-8 -*-
from multiprocessing.dummy import Pool as ThreadPool
def getsource(url):
        pass
pool = ThreadPool(1)
try:
        results = pool.map(getsource, url)
except Exception:
        pass

服務(wù)器代理

我選擇的阿里云服務(wù)器在進(jìn)行爬蟲代理爬取的時(shí)候,經(jīng)歷了三個(gè)環(huán)節(jié):

  • 服務(wù)器配置(根據(jù)服務(wù)器官方文檔進(jìn)行)
  • 爬蟲運(yùn)行環(huán)境設(shè)置(主要是Mysql及Python擴(kuò)展庫(kù)配置)
  • 遠(yuǎn)程連接(windows自帶的mstsc進(jìn)程)

關(guān)于這些環(huán)節(jié)转培,網(wǎng)上都能找到相應(yīng)教程

非典型又是什么恶导?

到以上為止,一個(gè)基礎(chǔ)的Python爬蟲的常規(guī)構(gòu)造過(guò)程包括但絕不限于上文提到的內(nèi)容堡距。
還有正則表達(dá)式甲锡,去重判斷,或者是發(fā)送包的Form Data需要加密羽戒,構(gòu)造爬蟲的時(shí)候不僅可以選擇基于 HttpClient的爬蟲缤沦,還可以選擇內(nèi)置于瀏覽器引擎的爬蟲(PhantomJS,Selenium)等細(xì)節(jié)本文沒有提到易稠。但是由于文章的重點(diǎn)并不是典型的爬蟲寫法缸废,所以點(diǎn)到即止。

如果就以上提到深入下去驶社,可以說(shuō)日常生活中絕大部分能夠接觸到的網(wǎng)頁(yè)企量,都可以用上述提到的內(nèi)容進(jìn)行信息爬取。
但是如果我沒有接下來(lái)提到的這個(gè)項(xiàng)目亡电,記錄的角度可能就不是現(xiàn)在這樣的了届巩。

所謂非典型

首先要解決一個(gè)問(wèn)題:為什么我叫這個(gè)項(xiàng)目為非典型爬蟲。
這里主要介紹此類非典型爬蟲適用的網(wǎng)頁(yè)特性份乒,以及具體的代碼實(shí)現(xiàn)方法恕汇。

網(wǎng)頁(yè)對(duì)象特性

像是上文中提到過(guò)的通過(guò)模擬瀏覽器發(fā)送請(qǐng)求,在獲取信息后使用結(jié)點(diǎn)(BeautifulSoup或者Xpath及正則表達(dá)式)進(jìn)行所需數(shù)據(jù)段的訪問(wèn)或辖,可以說(shuō)是一種萬(wàn)能的獲取數(shù)據(jù)的方法瘾英。
但是就像下面關(guān)于BILIBILI用戶頁(yè)面的圖片中,network-Headers里顯示的一樣颂暇,用戶的信息是單獨(dú)發(fā)過(guò)來(lái)的json文件(Response Headers: Content-Type: application/json; charset=utf-8)缺谴。對(duì)于json文件就存在著更加便捷的訪問(wèn)方式。
在了解了網(wǎng)頁(yè)內(nèi)容的基礎(chǔ)上進(jìn)行這樣的操作耳鸯,就仿佛把獲取信息和信息篩選這兩個(gè)步驟合并了湿蛔,在處理數(shù)據(jù)上無(wú)疑輕松了不少。


headers.png

Myinfo請(qǐng)求返回?cái)?shù)據(jù)preview:

myinfo_preview.png

Getinfo返回?cái)?shù)據(jù)preview:

getinfo_preview.png

從對(duì)比可以發(fā)現(xiàn)县爬,MyInfo中和GetInfo兩個(gè)請(qǐng)求返回的都是json內(nèi)容煌集,區(qū)別在于MyInfo獲取方式為GET,GetInfo獲取方式為POST捌省。
Json內(nèi)容的返回包使后續(xù)處理信息變得十分簡(jiǎn)便苫纤,只需要借用庫(kù)函數(shù)json.loads()就可以實(shí)現(xiàn)對(duì)返回?cái)?shù)據(jù)的提取,避免了分析網(wǎng)頁(yè)相對(duì)結(jié)點(diǎn)提取信息的步驟。
而如果對(duì)GetInfo網(wǎng)站返回的json數(shù)據(jù)進(jìn)行分析卷拘,可以發(fā)現(xiàn)返回包中已經(jīng)包含其關(guān)注人的ID的list喊废,對(duì)這個(gè)list的id進(jìn)行遍歷爬取,又可以獲得一系列活躍用戶的id栗弟,這樣應(yīng)該可以對(duì)特定大ip的用戶人群進(jìn)行用戶類型統(tǒng)計(jì)污筷。(有待完善)

attention_list.png

返回包處理&判重

JS文件處理

jsDict = json.loads(jsoncontent)
if jsDict['status'] == True:
        pass  #use the dict to take out message in the jsoncontent

判重

  • 數(shù)據(jù)直接存入數(shù)據(jù)庫(kù),并通過(guò)PRIMARY KEY(id)判斷是否已存在于數(shù)據(jù)庫(kù)乍赫。
  • 通過(guò)for i in range()語(yǔ)句瓣蛀,程序員自己定制爬取用戶段
    在這兩個(gè)判重條件下,去重變成了似乎不是那么重要的東西(僅限本項(xiàng)目

數(shù)據(jù)庫(kù)重復(fù)信息顯示:

try:
        pass  #codes of pushing the data into a table
except MySQLdb.Error, e:
print "Mysql_Error %d: %s" % (e.args[0], e.args[1]) # if is the same, print error message

總結(jié)

Python寫就的典型爬蟲基本可以應(yīng)對(duì)常見的大部分網(wǎng)站雷厂,而此次介紹的非典型爬蟲案例惋增,則是根據(jù)個(gè)別網(wǎng)頁(yè)特性進(jìn)行針對(duì)方案寫就的,在獲取專門化的信息上提供了另外一種思路改鲫。
在想要得到的資料需要用一大串正則表達(dá)式才能夠匹配到之時(shí)诈皿,如果資料的獲取可以通過(guò)類似更加便捷的方式獲取,這樣的思路無(wú)疑會(huì)使代碼功能得到簡(jiǎn)化像棘。
但是鑒于并非所有的網(wǎng)站都用相同請(qǐng)求獲得用戶信息稽亏,真的必須使用正則的時(shí)候肯定也不少。在尋找快捷途徑的之前缕题,還是要求程序員要有扎實(shí)的基本功啊截歉。(sign

參考項(xiàng)目/代碼

Requests: HTTP for Humans
Bilibili用戶信息
Bilibili模擬登陸
post 相比get 有很多優(yōu)點(diǎn),為什么現(xiàn)在的HTTP通信中大多數(shù)請(qǐng)求還是使用get
使用python+xpath獲取下載鏈接
Beautiful Soup Documentation
用map函數(shù)來(lái)完成Python并行任務(wù)的簡(jiǎn)單示例(對(duì)于multiprocessing.dummy的應(yīng)用)
Python: what are the differences between the threading and multiprocessing modules?
如何應(yīng)對(duì)網(wǎng)站反爬蟲策略烟零?如何高效地爬大量數(shù)據(jù)?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瘪松,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瓶摆,更是在濱河造成了極大的恐慌凉逛,老刑警劉巖性宏,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件群井,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡毫胜,警方通過(guò)查閱死者的電腦和手機(jī)书斜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酵使,“玉大人荐吉,你說(shuō)我怎么就攤上這事】谟妫” “怎么了样屠?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我痪欲,道長(zhǎng)悦穿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任业踢,我火速辦了婚禮栗柒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘知举。我一直安慰自己瞬沦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布雇锡。 她就那樣靜靜地躺著逛钻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪遮糖。 梳的紋絲不亂的頭發(fā)上绣的,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音欲账,去河邊找鬼屡江。 笑死,一個(gè)胖子當(dāng)著我的面吹牛赛不,可吹牛的內(nèi)容都是我干的惩嘉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼踢故,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼文黎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起殿较,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤耸峭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后淋纲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劳闹,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年洽瞬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了本涕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伙窃,死狀恐怖菩颖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情为障,我是刑警寧澤晦闰,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布放祟,位于F島的核電站,受9級(jí)特大地震影響呻右,放射性物質(zhì)發(fā)生泄漏舞竿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一窿冯、第九天 我趴在偏房一處隱蔽的房頂上張望骗奖。 院中可真熱鬧,春花似錦醒串、人聲如沸执桌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)仰挣。三九已至,卻和暖如春缠沈,著一層夾襖步出監(jiān)牢的瞬間膘壶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工洲愤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颓芭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓柬赐,卻偏偏與公主長(zhǎng)得像亡问,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肛宋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容

  • GitHub 上有一個(gè) Awesome - XXX 系列的資源整理,資源非常豐富州藕,涉及面非常廣。awesome-p...
    若與閱讀 18,656評(píng)論 4 418
  • 基礎(chǔ)知識(shí) HTTP協(xié)議 我們?yōu)g覽網(wǎng)頁(yè)的瀏覽器和手機(jī)應(yīng)用客戶端與服務(wù)器通信幾乎都是基于HTTP協(xié)議酝陈,而爬蟲可以看作是...
    腩啵兔子閱讀 1,488評(píng)論 0 17
  • 聲明:本文講解的實(shí)戰(zhàn)內(nèi)容床玻,均僅用于學(xué)習(xí)交流,請(qǐng)勿用于任何商業(yè)用途沉帮! 一锈死、前言 強(qiáng)烈建議:請(qǐng)?jiān)陔娔X的陪同下,閱讀本文...
    Bruce_Szh閱讀 12,712評(píng)論 6 28
  • 1 前言 作為一名合格的數(shù)據(jù)分析師遇西,其完整的技術(shù)知識(shí)體系必須貫穿數(shù)據(jù)獲取馅精、數(shù)據(jù)存儲(chǔ)严嗜、數(shù)據(jù)提取粱檀、數(shù)據(jù)分析、數(shù)據(jù)挖掘漫玄、...
    whenif閱讀 18,074評(píng)論 45 523
  • 一寸光陰一寸金茄蚯,寸金難買寸光陰压彭。光陰似箭,日月如梭渗常,又是一年高考季壮不。 有人說(shuō),沒有經(jīng)歷過(guò)高考的人生是不...
    木易yyH閱讀 644評(píng)論 0 0