SCRAPY解----草譯一篇得雨帝(Gotrained)的講義,供參考2019-03-04

文章原文地址:https://python.gotrained.com/scrapy-tutorial-web-scraping-craigslist/

爬的目標(biāo)網(wǎng)站;Craigslist

爬蟲(chóng)初步

安裝:pip install scrapy,用蘋(píng)果或李牛的高端用戶(hù)需要在前面加上sudo

創(chuàng)建項(xiàng)目

Scrapy startproject craigslist

craigslist是項(xiàng)目名稱(chēng)。

創(chuàng)建一只小蛛蛛(SPIDER)

在終端進(jìn)入文件夾craigslist,使用genspider命令,建立一個(gè)小蛛蛛。

如在這個(gè)項(xiàng)目中,我們用如下命令:

scrapy genspider jobs https://newyork.craigslist.org/search/egr

編輯小蛛蛛

在craiglist文件夾,你可以看出項(xiàng)目的文件情況:

現(xiàn)在你會(huì)發(fā)現(xiàn)在,在spiders文件夾里,有一個(gè)名為job.py的文件,就是我們剛剛創(chuàng)建的小蛛蛛。

打開(kāi)編輯器,開(kāi)始編輯這個(gè)東東:

# -*- coding: utf-8 -*-

import scrapy

class JobsSpider(scrapy.Spider):

? ? name = "jobs"

? ? allowed_domains = ["craigslist.org"]

? ? start_urls = ['https://newyork.craigslist.org/search/egr']

? ? def parse(self, response):

? ? ? ? pass

解釋一個(gè)這個(gè)文件:

name,是我們給這個(gè)小蛛蛛起的名字,這個(gè)小蛛蛛名為jobs

allowed-domains列出了小蛛蛛可以活動(dòng)的范圍

start_urls列出了一個(gè)或多個(gè)小蛛蛛開(kāi)起運(yùn)動(dòng)的起點(diǎn)。

Parse是小蛛蛛的主函數(shù),注意,不要,千萬(wàn)不要改這個(gè)函數(shù)的名字。如有所需,你可以增加其他函數(shù)。

提示:如果你用和講義相同的方法創(chuàng)建了小蛛蛛,它會(huì)自己在start_urls中加上http://,一定要注意檢查,如果出現(xiàn)了重復(fù)的http://,蟲(chóng)子不會(huì)正常運(yùn)動(dòng)。

最簡(jiǎn)單的一只,單項(xiàng)爬蟲(chóng)

刪除pass,在函數(shù)中加入以下行:

titles = response.xpath('//a[@class="result-title hdrlnk"]/text()').extract()

啥意思?

titles是根據(jù)一定的規(guī)則解析出來(lái)的內(nèi)容組成的列表

response是一個(gè)命令,獲取整個(gè)頁(yè)面的HTML。如果:

print(response)

你得到什么結(jié)果?

<200 http://*****>

星號(hào)代表你請(qǐng)求的鏈接。

如果:

print(response.body)

你則會(huì)得到頁(yè)面主體的代碼。

你可以用xpath()來(lái)解析。命令為:

response.xpath()

Xpath是個(gè)復(fù)雜的話題,但有個(gè)簡(jiǎn)單的方法讓你得到相應(yīng)的xpath,打開(kāi)你的Chrone瀏覽器,復(fù)制剛才的鏈接,選取相應(yīng)的頁(yè)面元素,單擊右鍵,選取“檢查”(inspect)

你就會(huì)看到這部分元素的HTML代碼,如:

<a href="/brk/egr/6085878649.html" data-id="6085878649" class="result-title hdrlnk">Chief Engineer</a>

這是一個(gè)鏈接,鏈接文字是“Chief Engineer” ,可以用text()查看。

其class被標(biāo)為:result-title hdrlnk

用extract()可以獲取列表中的項(xiàng)。

我們要把title項(xiàng)顯示出來(lái):

print(titles)

于是這個(gè)小蛛蛛的完整代碼是:

# -*- coding: utf-8 -*-

import scrapy

class JobsSpider(scrapy.Spider):

? ? name = "jobs"

? ? allowed_domains = ["craigslist.org"]

? ? start_urls = ['https://newyork.craigslist.org/search/egr']

? ? def parse(self, response):

? ? ? ? titles = response.xpath('//a[@class="result-title hdrlnk"]/text()').extract()

? ? ? ? print(titles)

動(dòng)起來(lái),蟲(chóng)子

在終端項(xiàng)目文件夾下,輸入以下命令,開(kāi)動(dòng)蟲(chóng)子。

scrapy crawl jobs

Jobs是這個(gè)蟲(chóng)子的名字。

終端將列表結(jié)果打印出來(lái)。

接下來(lái),我們可以用yield命令,將列表中的內(nèi)容取出來(lái),放入一個(gè)字典:

for title in titles:

? ? yield {'Title': title}

于是這個(gè)蟲(chóng)子的完整美圖如下:

# -*- coding: utf-8 -*-

import scrapy

class JobsSpider(scrapy.Spider):

? ? name = "jobs"

? ? allowed_domains = ["craigslist.org"]

? ? start_urls = ['https://newyork.craigslist.org/search/egr']

? ? def parse(self, response):

? ? ? ? titles = response.xpath('//a[@class="result-title hdrlnk"]/text()').extract()

? ? ? ? for title in titles:

? ? ? ? ? ? yield {'Title': title}

將爬取的結(jié)果存到CSV等類(lèi)型的文件里

可以在前述爬蟲(chóng)運(yùn)行命令后加上 -o 指定文件名,將結(jié)果存入相應(yīng)文件,文件類(lèi)型包括csv,json,xml。

scrapy crawl jobs -o result-titles.csv

第二只,單頁(yè)爬蟲(chóng)

如果你想得到與工作有關(guān)的其他項(xiàng)目,你是不是應(yīng)該多寫(xiě)幾個(gè)單項(xiàng)爬蟲(chóng),來(lái)讓它們完成不同的工作?

答案是否定的,你不必如此。你可以把頁(yè)面每一個(gè)工作相關(guān)的元素的容器抓取下來(lái),解出其中的項(xiàng)目。

例如,在這個(gè)頁(yè)上,https://newyork.craigslist.org/search/egr

你查看元素,會(huì)看到如相內(nèi)容:

在頁(yè)上,有列表項(xiàng)(li)標(biāo)志,前面有個(gè)小三角,點(diǎn)擊,可以展開(kāi)每個(gè)列表項(xiàng),在其中,包含你需要的與該項(xiàng)工作有關(guān)的全部信息,你可以把這個(gè)列表項(xiàng)視為封套或容器。

Li標(biāo)簽的class被指定為“result-row”,在其中,包括一個(gè)鏈接,還有一個(gè)段落標(biāo)簽(p),這個(gè)標(biāo)簽的class被指定為”result-info”,我們把這人容器拿出來(lái),就需要在爬蟲(chóng)函數(shù)里寫(xiě)下:

jobs = response.xpath('//p[@class="result-info"]')

然后解出其中的title項(xiàng)目:

for job in jobs:

? ? title = job.xpath('a/text()').extract_first()

? ? yield{'Title':title}

這是一個(gè)循環(huán),其中,你無(wú)需再用response了,你使用了一個(gè)名為job的選擇項(xiàng)。在解析容器時(shí),我們用的是//,指示xpath是從<html>直到<p>,而現(xiàn)在,我們則不用//,因?yàn)楝F(xiàn)在的選擇是以jobs為基礎(chǔ)的。你也可以用.//

我們使用extrat_first(),而不是extract(), 因?yàn)槲覀冎幌氲靡淮蔚玫揭粋€(gè)值。

現(xiàn)在我們添加其他項(xiàng)目:

for job in jobs:

? ? title = job.xpath('a/text()').extract_first()

? ? address = job.xpath('span[@class="result-meta"]/span[@class="result-hood"]/text()').extract_first("")[2:-1]

? ? relative_url = job.xpath('a/@href').extract_first()

? ? absolute_url = response.urljoin(relative_url)

? ? yield{'URL':absolute_url, 'Title':title, 'Address':address}

我們加入了address等項(xiàng)目。注意,通過(guò)xpath我們得到的是一個(gè)相對(duì)鏈接,我們需要用response.urljion()轉(zhuǎn)換成完整的鏈接。

第三只蟲(chóng)子:多頁(yè)蟲(chóng)子

在內(nèi)容比較多時(shí),網(wǎng)站采取了分頁(yè)技術(shù),這樣,我們有必要通過(guò)獲取“下一頁(yè)”的地址,將所有的項(xiàng)目都拿下來(lái)。

在這個(gè)頁(yè)面上,下一頁(yè)next的HTML代碼是這樣的:

<a href="/search/egr?s=120" class="button next" title="next page">next > </a>

于是,我們?cè)诘诙幌x(chóng)子的基礎(chǔ)上,加入以下代碼,取得下一頁(yè)的鏈接,傳到主函數(shù)self.parse,讓它繼續(xù)獲取其中的項(xiàng)目。

relative_next_url = response.xpath('//a[@class="button next"]/@href').extract_first()

absolute_next_url = response.urljoin(relative_next_url)

yield Request(absolute_next_url, callback=self.parse)

你也可以不寫(xiě)callback=self.parse,因?yàn)檫@是默認(rèn)的。

另外,由于使用了Request,我們必須將它引入:

From scrapy import Request

注意,R是大寫(xiě)。

運(yùn)行下,可以得到更多的結(jié)果。

第四只蟲(chóng)子 獲取詳細(xì)頁(yè)內(nèi)容

下面,我們要讓小蛛蛛打開(kāi)其獲取的鏈接,然后從中取出有關(guān)工作的描述。在第三只蟲(chóng)子基礎(chǔ)上,我們繼續(xù)以下內(nèi)容。第三只蟲(chóng)子讓我們得到了絕對(duì)鏈接,標(biāo)題和地址:

yield{'URL':absolute_url, 'Title':title, 'Address':address}

我們要建立一個(gè)函數(shù),把已經(jīng)取得的鏈接傳遞給它,讓它獲得詳細(xì)頁(yè),這個(gè)函數(shù)我們將它命名為parse_page()。我們還將用meta.get()傳遞已經(jīng)取得的項(xiàng)目。

yield Request(absolute_url, callback=self.parse_page, meta={'URL': absolute_url, 'Title': title, 'Address':address})

這個(gè)函數(shù)總體是這樣的:

def parse_page(self, response):

? ? url = response.meta.get('URL')

? ? title = response.meta.get('Title')

? ? address = response.meta.get('Address')

? ? description = "".join(line for line in response.xpath('//*[@id="postingbody"]/text()').extract())

? ? compensation = response.xpath('//p[@class="attrgroup"]/span/b/text()')[0].extract()

? ? employment_type = response.xpath('//p[@class="attrgroup"]/span/b/text()')[1].extract()

? ? yield{'URL': url, 'Title': title, 'Address':address, 'Description':description}

你已經(jīng)注意到了,我們加入了一個(gè)變量,discription,由于工作描述可能多于一個(gè)段落,所以要用jion()把它們合起來(lái)。

同樣的,我們加入comensation,以及employment_type。

設(shè)置settings.py

可以設(shè)置CSV的輸出:

FEED_EXPORT_FIELDS = ['Title','URL', 'Address', 'Compensation', 'Employment Type','Description']

可以設(shè)定代理,讓你的蟲(chóng)子運(yùn)動(dòng)看起來(lái)像個(gè)正常的瀏覽行為。

USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'

可以設(shè)定遲延,如3秒或在一定區(qū)間。

完整代碼:

import scrapy

from scrapy import Request

class JobsSpider(scrapy.Spider):

? ? name = "jobs"

? ? allowed_domains = ["craigslist.org"]

? ? start_urls = ["https://newyork.craigslist.org/search/egr"]

? ? def parse(self, response):

? ? ? ? jobs = response.xpath('//p[@class="result-info"]')

? ? ? ? for job in jobs:

? ? ? ? ? ? relative_url = job.xpath('a/@href').extract_first()

? ? ? ? ? ? absolute_url = response.urljoin(relative_url)

? ? ? ? ? ? title = job.xpath('a/text()').extract_first()

? ? ? ? ? ? address = job.xpath('span[@class="result-meta"]/span[@class="result-hood"]/text()').extract_first("")[2:-1]

? ? ? ? ? ? yield Request(absolute_url, callback=self.parse_page, meta={'URL': absolute_url, 'Title': title, 'Address':address})

? ? ? ? relative_next_url = response.xpath('//a[@class="button next"]/@href').extract_first()

? ? ? ? absolute_next_url = "https://newyork.craigslist.org" + relative_next_url

? ? ? ? yield Request(absolute_next_url, callback=self.parse)

? ? def parse_page(self, response):

? ? ? ? url = response.meta.get('URL')

? ? ? ? title = response.meta.get('Title')

? ? ? ? address = response.meta.get('Address')

? ? ? ? description = "".join(line for line in response.xpath('//*[@id="postingbody"]/text()').extract())

? ? ? ? compensation = response.xpath('//p[@class="attrgroup"]/span[1]/b/text()').extract_first()

? ? ? ? employment_type = response.xpath('//p[@class="attrgroup"]/span[2]/b/text()').extract_first()


? ? ? ? yield{'URL': url, 'Title': title, 'Address':address, 'Description':description, 'Compensation':compensation, 'Employment Type':employment_type}

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

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

  • 桃花奇遇(7) 琪兒一醒來(lái),發(fā)現(xiàn)自己躺在一張豪華的床上,看看四周,發(fā)現(xiàn)無(wú)論是裝修還是風(fēng)格,她都喜歡。“我明明在和惠...
    可兒君鈞閱讀 497評(píng)論 2 2
  • 『一心讀書(shū)』荔枝直播間《洛克菲勒留給兒子的38封信》第三封信分享PPT 由『一心讀書(shū)』整理《洛克菲勒留給兒子的38...
    一心小茶館閱讀 1,217評(píng)論 22 14
  • 我知道你會(huì)回來(lái) 在田野里長(zhǎng)出新綠的日子 在天空飄蕩燕子鳴叫的日子 在我的門(mén)前溪水歡快的日子 在我的臉上暖出紅暈的日...
    代號(hào)1743閱讀 388評(píng)論 0 6
  • 文/花貓 暑期回來(lái)在群里我收到這樣一封信,來(lái)自輔導(dǎo)班的班主任。面對(duì)十一月份的教師資格證考試,老師們也是沒(méi)日沒(méi)夜的準(zhǔn)...
    森林里的花貓閱讀 369評(píng)論 2 2
  • 老文表叔會(huì)編制各色的草帽,有王冠狀的,藤葉修飾整齊,厚重緊實(shí);也有簡(jiǎn)易速成的,把野蕨菜連莖帶葉折下來(lái),照腦袋尺寸繞...
    西門(mén)楊曉羊閱讀 409評(píng)論 2 6

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