第二個(gè)爬蟲

[TOC]

目標(biāo)

實(shí)現(xiàn)爬蟲的完整運(yùn)行啊掏,登陸,js解析衰猛,url去重迟蜜,通過中間件進(jìn)行功能擴(kuò)展,考慮驗(yàn)證碼破解啡省,頁面更新

js解析娜睛,可以考慮Pyv8,PythonWebKit卦睹,Selenium畦戒,PhantomJS,Ghost.py等
數(shù)據(jù)存儲(chǔ)结序,考慮用mongodb
去重兢交,考慮用BitVector

完整的爬取

scrapy里,先定義了starturl笼痹,然后parse函數(shù)會(huì)自動(dòng)去讀取這些url配喳,并做解析
可以通過request

Request(item['href'],callback=self.parescontent)

Scrapy uses Request and Response objects for crawling web sites.

Typically, Request objects are generated in the spiders and pass across the system until they reach the Downloader, which executes the request and returns a Response object which travels back to the spider that issued the request.

模擬登陸

def start_requests(self):
        return [Request("https://www.zhihu.com/login", callback = self.post_login)]  #重寫了爬蟲類的方法, 實(shí)現(xiàn)了自定義請(qǐng)求, 運(yùn)行成功后會(huì)調(diào)用callback回調(diào)函數(shù)

    #FormRequeset
    def post_login(self, response):
        print 'Preparing login'
        #下面這句話用于抓取請(qǐng)求網(wǎng)頁后返回網(wǎng)頁中的_xsrf字段的文字, 用于成功提交表單
        xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]
        print xsrf
        #FormRequeset.from_response是Scrapy提供的一個(gè)函數(shù), 用于post表單
        #登陸成功后, 會(huì)調(diào)用after_login回調(diào)函數(shù)
        return [FormRequest.from_response(response,   
                            formdata = {
                            '_xsrf': xsrf,
                            'email': '123456',
                            'password': '123456'
                            },
                            callback = self.after_login
                            )]

配置代理頭

調(diào)用頁面解析時(shí)候可以指定header頭,requset的定義如下

class Request(object_ref):

    def __init__(self, url, callback=None, method='GET', headers=None, body=None,
                 cookies=None, meta=None, encoding='utf-8', priority=0,
                 dont_filter=False, errback=None):

        self._encoding = encoding  # this one has to be set first
        self.method = str(method).upper()
        self._set_url(url)
        self._set_body(body)
        assert isinstance(priority, int), "Request priority not an integer: %r" % priority
        self.priority = priority

        assert callback or not errback, "Cannot use errback without a callback"
        self.callback = callback
        self.errback = errback

        self.cookies = cookies or {}
        self.headers = Headers(headers or {}, encoding=encoding)
        self.dont_filter = dont_filter

        self._meta = dict(meta) if meta else None

實(shí)例化Request的時(shí)候凳干,可以直接指定header

比如Request('http://www.baidu.com',callback=self.parescontent, method='GET', headers=sth, encoding='utf-8')

如果要配置多個(gè)header晴裹,并且自動(dòng)配置也很簡(jiǎn)單,方式如下

import random
headers = [headera,headerb,headerc]
Request('http://www.baidu.com',callback=self.parescontent, method='GET', headers=random.choice(headers) , encoding='utf-8')

布隆過濾器及改進(jìn)

布隆過濾器的思想 -- 不追求完美

在quora上救赐,有個(gè)問題問涧团,人們最常犯的錯(cuò)誤是哪些,其中一個(gè)就是追求完美经磅。
在it領(lǐng)域泌绣,為了讓系統(tǒng)完美化,比如之前涉及存儲(chǔ)系統(tǒng)预厌,去重時(shí)想達(dá)到完美的標(biāo)準(zhǔn)阿迈,花的代價(jià)是2小時(shí),如果稍加改動(dòng)轧叽,可以讓代價(jià)降低到1分鐘左右苗沧,只有本來的百分之一不到。

布隆過濾器的思想炭晒,也是如此待逞。

布隆過濾器的應(yīng)用 - 使用案例

squid

squid里的cache digests 用的是布隆過濾器

chrom

chrom里判斷惡意鏈接,也是用的布隆過濾器

hbase里也用了bloom filter

如圖
bloom filter在hbase里的用法比較有意思网严,它先判斷大小识樱,再做bf,這樣能讓查詢速度加快幾十倍

布隆過濾器的缺點(diǎn)和改進(jìn)

缺點(diǎn)

布隆過濾器的缺點(diǎn)是錯(cuò)判震束,就是說怜庸,不在里面的,可能判斷成在里面驴一,但是在里面的休雌,一定不會(huì)錯(cuò),而且肝断,無法刪除

改進(jìn)

改進(jìn)1 多bit

bloom filter其實(shí)就是bitmaq的改進(jìn)杈曲,bitmap是單個(gè)hash,而bf是多個(gè)hash胸懈,本質(zhì)上担扑,都是一個(gè)bit只能存有或者沒有兩種狀態(tài)
可以考慮用多bit記錄的方式,這種方法趣钱,就是本來每個(gè)bit不是0就是1涌献,現(xiàn)在可以記錄其它的,如果add一個(gè)元素首有,把對(duì)應(yīng)bit的數(shù)字加1即可
如果要del一個(gè)元素燕垃,對(duì)應(yīng)位置的數(shù)字減1即可
好處是枢劝,可以刪除元素
缺點(diǎn)是,可能會(huì)有位溢出卜壕,另外您旁,錯(cuò)判還是會(huì)發(fā)生,速度也慢了

改進(jìn)2 白名單

還有種改進(jìn)方式是對(duì)一些常見的url加到白名單里
這種改進(jìn)是不錯(cuò)的選擇轴捎,對(duì)于某些不考慮過濾的url鹤盒,可以先判斷一下,剩下的url錯(cuò)判就錯(cuò)判侦副,對(duì)結(jié)果影響是可以接受

布隆過濾器的細(xì)節(jié) - 算法的實(shí)現(xiàn)

下面用pybloom演示一下布隆過濾器的用法

from pybloom import BloomFilter
from pybloom import benchmarks
f = BloomFilter(capacity=100000, error_rate=0.1)
# [f.add(x) for x in range(102)]
[f.add(x) for x in range(1001)]

for x in range(1001, 100000000):
    if x in f:
        print x

可以看出侦锯,布隆過濾器,還是比較高效的一種數(shù)據(jù)結(jié)構(gòu)

存儲(chǔ)

先安裝monogdb秦驯,創(chuàng)建一個(gè)庫叫l(wèi)ei尺碰,再建個(gè)表,叫做questions
然后在setings.py中配置mongodb的ip汇竭,port葱蝗,db name,collection name這些

ITEM_PIPELINES = {
    'tutorial.pipelines.MongoDBPipeline': 300,
}
MONGODB_SERVER = "192.168.100.110"
MONGODB_PORT = 27017
MONGODB_DB = "lei"
MONGODB_COLLECTION = "questions"

# DOWNLOAD_DELAY = 5  # 抓取的延遲

然后建一個(gè)pipelines.py细燎,這個(gè)pipelines是用來處理item的两曼,把item解析后存到mongodb里,代碼也很簡(jiǎn)單

import pymongo
from scrapy.conf import settings
from scrapy.exceptions import DropItem
from scrapy import log


class MongoDBPipeline(object):
    def __init__(self):
        connection = pymongo.MongoClient(
            settings['MONGODB_SERVER'],
            settings['MONGODB_PORT']
        )
        db = connection[settings['MONGODB_DB']]
        self.collection = db[settings['MONGODB_COLLECTION']]

    def process_item(self, item, spider):
        for data in item:
            if not data:
                raise DropItem("Missing data!")
        self.collection.update({'url': item['url']}, dict(item), upsert=True)
        log.msg("Question added to MongoDB database!",level=log.DEBUG, spider=spider)
        return item

執(zhí)行scrapy crawl 51job玻驻,在robomon里即可看到爬取的結(jié)果

{
"_id" : ObjectId("57cfcebc2e45cfeb955b5483"),
"url" : "http://jobs.51job.com/nanjing-xwq/81462838.html?s=0",
"job_pay" : "6000-7999/月",
"company_type" : "民營公司",
"company_scale" : "50-150人",
"company_industry" : "影視/媒體/藝術(shù)/文化傳播",
"job_describe" : "現(xiàn)招一名完美的男孩他要坐立筆直悼凑,言行端正。他要行動(dòng)迅速璧瞬,不出聲響户辫。他可以在大街上吹口哨,但在該保持安靜的地方不吹口哨嗤锉。他看起來要精神愉快渔欢,對(duì)每個(gè)人都笑臉相迎,從不生氣瘟忱。他要禮貌待人奥额,尊重女人他愿意說一口純正的普通話,而不是家鄉(xiāng)話访诱。他在與女孩的相處中不緊張垫挨。他和自己的母親相處融洽,與她的關(guān)系最為親近触菜。他不虛偽九榔,也不假正經(jīng),而是健康,快樂哲泊,充滿活力剩蟀。",
"job_title" : "現(xiàn)招一名完美的男孩 投資理財(cái)顧問助理總助"
}

遇到的問題

beautifulsoup解析頁面,結(jié)果缺失的問題

在解析http://search.51job.com/list/070200,070201,0000,00,9,99,%2B,2,1.html時(shí)攻旦,這個(gè)頁面的url一直解析不出來所有的url
一直以為是我代碼寫的有問題喻旷,坑了一上午,發(fā)現(xiàn)是解析器的問題 fire :-(

如果用bs4牢屋,載入時(shí)候html5不行,就換html槽袄,soup = BeautifulSoup(temp, "html.parser")

運(yùn)行時(shí)報(bào)錯(cuò)

提示 AttributeError: 'list' object has no attribute 'iteritems'
原因是在settings文件里烙无,配置item pipelines的時(shí)候,沒有指定順序遍尺,正確的方式如下:

ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}

items是根據(jù)數(shù)字大小截酷,從低到高通過pipelines,數(shù)字的范圍是0-1000

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末乾戏,一起剝皮案震驚了整個(gè)濱河市迂苛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鼓择,老刑警劉巖三幻,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異呐能,居然都是意外死亡念搬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門摆出,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朗徊,“玉大人,你說我怎么就攤上這事偎漫∫遥” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵象踊,是天一觀的道長(zhǎng)温亲。 經(jīng)常有香客問我,道長(zhǎng)通危,這世上最難降的妖魔是什么铸豁? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮菊碟,結(jié)果婚禮上节芥,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好头镊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布蚣驼。 她就那樣靜靜地躺著,像睡著了一般相艇。 火紅的嫁衣襯著肌膚如雪颖杏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天坛芽,我揣著相機(jī)與錄音留储,去河邊找鬼。 笑死咙轩,一個(gè)胖子當(dāng)著我的面吹牛获讳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播活喊,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼丐膝,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了钾菊?” 一聲冷哼從身側(cè)響起帅矗,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎煞烫,沒想到半個(gè)月后浑此,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡红竭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年尤勋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茵宪。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡最冰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出稀火,到底是詐尸還是另有隱情暖哨,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布凰狞,位于F島的核電站篇裁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏赡若。R本人自食惡果不足惜达布,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逾冬。 院中可真熱鬧黍聂,春花似錦躺苦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脐区,卻和暖如春愈诚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牛隅。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工炕柔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倔叼。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓汗唱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親丈攒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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