Scrapy抓取關(guān)鍵字(支持百度誓禁、搜狗等)

image.png

前幾天由于工作需要懈息,需要抓取一個特定的關(guān)鍵字來提取百度中搜索的結(jié)果,并保留50頁的數(shù)據(jù)存入數(shù)據(jù)庫或者.csv文件中摹恰。(每天抓取一次)

1.項目需要環(huán)境安裝

1)scrapy+selenium+chrome(phantomjs)
關(guān)于爬蟲所依賴環(huán)境的安裝辫继,我前面已經(jīng)介紹過了。大家可以參考http://www.reibang.com/p/1890e9b3ba37這篇文章我的詳細介紹即可俗慈。
2)mysql+redis安裝 數(shù)據(jù)庫安裝可查閱百度(很簡單)

2.項目開發(fā)流程介紹

我們需要模擬用戶行為在瀏覽器的輸入框輸入指定的關(guān)鍵字骇两,并模擬點擊獲取想要的數(shù)據(jù),將此頁面展示的數(shù)據(jù)進行保存姜盈、過濾,并模擬翻頁配阵,抓取此關(guān)鍵字的前50頁展示馏颂,獲取我們想要的數(shù)據(jù)示血,存入.csv文件或者redis數(shù)據(jù)庫中,以便后面數(shù)據(jù)分析使用救拉。

3.開發(fā)代碼詳解

1)創(chuàng)建一個scrapy項目
scrapy startproject keyword_scrawl
scrapy genspider redistest baidu.com

  1. 代碼中各文件介紹
    settings.py是一個總配置文件:

BOT_NAME : 工程名字

SPIDER_MODULES:

NEWSPIDER_MODULE:

下面module的配置路徑

pipelines.py 這個是一個跟數(shù)據(jù)存儲相關(guān)的文件

middlewares.py 可以自定義难审,讓scrapy更加可控

items.py 這個文件有點類似于 django中的一個form,定義了數(shù)據(jù)保存的格式

亿絮,但是它要比django的form應(yīng)用簡單告喊,因為它的字段是十分單一的。
spider文件夾:這個文件夾中存放的是具體的某個網(wǎng)站的爬蟲.通過命令行派昧,我們可以創(chuàng)建出屬于自己的一個spider黔姜。

4.spider代碼詳解

def make_requests_from_url(self, url):
        if self.params['st_status'] == 1:
            return Request(url, meta={'keyword': self.keyword, 'engine':self.sousu, 'phantomjs':True})
        else:
            return Request(url)

首先修改spider中make_requests_from_url函數(shù),添加一個判斷蒂萎,當st_status==1時秆吵,我們在返回request對象時,添加一個meta五慈,并在meta中攜帶我們想要搜索的關(guān)鍵和需要訪問的瀏覽器地址纳寂。以及啟動phantomjs的指令。

class PhantomJSMiddleware(object):
    @classmethod
    def process_request(cls, request, spider):
        if request.meta.has_key('phantomjs'):
            keyword = request.meta.get('keyword')
            dcap = dict(DesiredCapabilities.PHANTOMJS)
            dcap["phantomjs.page.settings.userAgent"] = ('Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0')
            dcap["phantomjs.page.settings.AcceptLanguage"] = ('zh-CN,zh;q=0.9')
            driver = webdriver.PhantomJS(desired_capabilities=dcap)
            driver.set_page_load_timeout(100)
            driver.set_script_timeout(15)
            try:
                driver.get(request.url)
                if request.meta.get('engine') == 1:
                    driver.find_element_by_id("query").send_keys(keyword)
                    driver.find_element_by_class_name("swz").click()
                elif request.meta.get('engine') == 2:
                    driver.find_element_by_id("kw").send_keys(keyword)
                    driver.find_element_by_id("su").click()
                time.sleep(2)
                final_url = driver.current_url
                if final_url != request.url:
                    fullurl = final_url
                else:
                    fullurl = request.url
                content = driver.page_source.encode('utf-8','ignore')
                driver.quit()
                return HtmlResponse(fullurl, encoding='utf-8', body=content, request=request)
            except Exception, e:
                driver.quit()
                print e

其次修改middlewares中間件中的類方法process_request,此方法默認攜帶request和spider對象泻拦,在我們剛剛修改的make_requests_from_url方法中毙芜。我們可以在這里處理前面make_requests_from_url函數(shù)返回的Request請求,然后加載selenium争拐、phantomjs腋粥,從而獲取我們需要訪問的瀏覽器和關(guān)鍵字,此代碼會模擬用戶的行為去獲取關(guān)鍵字內(nèi)容陆错,然后將頁面的內(nèi)容返回給scrapy.http 中的HtmlResponse對象灯抛。這樣我們就可以在spider 內(nèi)的parse函數(shù)中獲取到剛剛抓取的內(nèi)容response.body。

    # 判斷頁面的返回狀態(tài)
        if int(response.status) >= 200 and int(response.status) < 400:
            if not self.params['redis_key']:
                a_list = response.xpath('//h3/a/@href').extract()
                for url in a_list:
                    if url.startswith('http://') != True and url.startswith('https://') !=True:
                        url = response.urljoin(url)
                    yield scrapy.Request(url=url, meta={'url':response.url}, callback=self.pang_bo, dont_filter=True)

                if response.meta.has_key('page') != True and self.sousu == 2:
                    flag = 1
                    for next_url in response.xpath('//div[@id="page"]/a/@href').extract():
                        if next_url.startswith('http://') != True and next_url.startswith('https://') !=True:
                            nextUrl = self.start_urls[0] + next_url
                            regex = 'pn=(\d+)'
                            page_number = re.compile(regex).search(nextUrl).group(1)
                            if page_number and flag:
                                flag = 0
                                # 抓取前50頁
                                for page in range(10,500,10):
                                    next_page = 'pn=' + str(page)
                                    old_page = re.compile(regex).search(nextUrl).group()
                                    nextUrl = nextUrl.replace(old_page, next_page)
                                    yield scrapy.Request(url=nextUrl, meta={'page':page}, callback=self.parse)

上面的代碼就是獲取剛剛網(wǎng)頁中展示的每一個搜索結(jié)果音瓷,并獲取到頁面規(guī)律对嚼,模擬翻頁50頁,將50頁的內(nèi)容全部遞交給self.pang_bo函數(shù)進行處理绳慎。在此做了一個頁面去重纵竖!

    # 處理item
    def parse_text(self, response):

        item = {}
        try:
            father_url = response.meta["url"]
        except:
            father_url = "''"
        try:
            item['title'] = response.xpath('//title/text()').extract_first().replace('\r\n','').replace('\n','').encode('utf-8')
        except:
            item['title'] = "''"
        item['url'] = response.url
        item['domain'] = ''
        item['crawl_time'] = time.strftime('%Y%m%d%H%M%S')
        item['keyword'] = ''
        item['Type_result'] = ''
        item['type'] = 'html'
        item['filename'] = 'yq_' + str(int(time.time())) + '_0' + str(rand5())+'.txt'
        item['referver'] = father_url
        item['like'] = ''
        item['transpond'] = ''
        item['comment'] = ''
        item['publish_time'] = ''
        return item
    def pang_bo(self, response):
        # 過略掉百度網(wǎng)頁
        if 'baidu.com' not in response.url and 'ctrip.com' not in response.url and 'baike.com' not in response.url:
            item = self.parse_text(response)
            content = soup_text(response.body)
            if len(content) > 3000:
                content = content[:3000]
            #elif len(content) == 0:
                #yield scrapy.Request(url=response.url, meta={'url':response.url, 'phantomjs':True}, callback=self.pang_bo)
            body = item['url']+','+item['crawl_time']+','+item['title'].replace(',','') +','+content+'\n'
            if '正在進入' == item['title']:
                file_name = os.path.join(self.filetxt,time.strftime('%Y%m%d%H')+'keyword.csv')
                with open(file_name, 'a') as b:
                    b.write(body)
            else:
                filename = os.path.join(self.filetxt,time.strftime('%Y%m%d%H')+'.csv')
                with open(filename, 'a') as f:
                    f.write(body)

# 過濾網(wǎng)頁源代碼
def soup_text(body):
    try:
        soup = BeautifulSoup(body, 'lxml')
        line = re.compile(r'\s+')
        line = line.sub(r'', soup.body.getText())
        p2 = re.compile(u'[^\u4e00-\u9fa5]')  # 中GDAC\u4e00\u9fa5
        str2 = p2.sub(r'', line)
        outStr = str2.strip(',')
    except:
        outStr = ''
    return outStr

這個代碼主要過略掉一些不需要的網(wǎng)站,然后提取item字段杏愤,和頁面body(這里過濾了源碼)然后將獲取到的內(nèi)容保存到.csv文件中靡砌。這只是一個簡簡單單的爬蟲,反爬的話就設(shè)置settings如下:

LOG_STDOUT = True    # 將進程所有的標準輸出(及錯誤)將會被重定向到log中(為了方便調(diào)試)
DOWNLOAD_DELAY=0.25    # 下載延時設(shè)置 單位秒
DOWNLOAD_TIMEOUT = 60  # 下載超時設(shè)置(單位秒)
CONCURRENT_ITEMS = 200  # 同時處理的itmes數(shù)量
CONCURRENT_REQUESTS = 16 # 同時并發(fā)的請求

今天的代碼到這里就介紹完了珊楼,還是想說:"做一個愛分享的程序員通殃,大家有什么疑問歡迎留言",如果覺得我的文章可以厕宗,歡迎關(guān)注和點贊画舌。謝謝各位堕担!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市曲聂,隨后出現(xiàn)的幾起案子霹购,更是在濱河造成了極大的恐慌,老刑警劉巖朋腋,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齐疙,死亡現(xiàn)場離奇詭異,居然都是意外死亡旭咽,警方通過查閱死者的電腦和手機贞奋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轻专,“玉大人忆矛,你說我怎么就攤上這事∏攵猓” “怎么了催训?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宗收。 經(jīng)常有香客問我漫拭,道長,這世上最難降的妖魔是什么混稽? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任采驻,我火速辦了婚禮,結(jié)果婚禮上匈勋,老公的妹妹穿的比我還像新娘礼旅。我一直安慰自己,他們只是感情好洽洁,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布痘系。 她就那樣靜靜地躺著,像睡著了一般饿自。 火紅的嫁衣襯著肌膚如雪汰翠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天昭雌,我揣著相機與錄音复唤,去河邊找鬼。 笑死烛卧,一個胖子當著我的面吹牛佛纫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呈宇,長吁一口氣:“原來是場噩夢啊……” “哼跟磨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起攒盈,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哎榴,沒想到半個月后型豁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡尚蝌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年迎变,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片飘言。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡衣形,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姿鸿,到底是詐尸還是另有隱情谆吴,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布苛预,位于F島的核電站句狼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏热某。R本人自食惡果不足惜腻菇,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昔馋。 院中可真熱鬧筹吐,春花似錦、人聲如沸秘遏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垄提。三九已至榔袋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铡俐,已是汗流浹背凰兑。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留审丘,地道東北人吏够。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锅知。 傳聞我的和親對象是個殘疾皇子播急,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355