Scrapy實戰:抓取本地論壇招聘內容 (一)

寫的內容越來越多,因此做成一個系列,謝謝大家。我將定期更新相關內容:
Scrapy實戰:抓取本地論壇招聘內容 (一)
Scrapy實戰:抓取本地論壇招聘內容 (二)

scrapy是專用的爬蟲框架,可以省卻好多自己寫爬蟲的內容,而且速度很有保證,所以讓我們用scrapy來爬取吧!

一、 分析網頁結構

開工之前,先看看網頁結構,我們要獲取的內容.

1. 先看url

url = http://bbs.cnnb.com/forum.php?mod=forumdisplay&fid=37&filter=author&orderby=dateline&typeid=366

很明顯,這是一個論壇,有五個參數,我們先一個一個刪除,看看有什么變化:

mod=forumdisplay # 這是論壇顯示方式,純文字還是圖片,大多數論壇都有這個,不能刪除
fid=37 # 暫時不明白,我猜是論壇板塊標記,不能刪除
filter=author #過濾發布人,不能刪除
orderby=dateline #按時間排序,時間降序,不能刪除
typeid=366 # 招聘類目,不能刪除

,經過測試,只要刪除了其中任何一個參數,頁面都不是我們想要的。我們當然要爬的不止一頁,點擊下一頁看看有什么變化。

http://bbs.cnnb.com/forum.php?mod=forumdisplay&fid=37&filter=author&orderby=dateline&typeid=366&page=2

多了一個參數,page=2, 很明顯這是控制顯示第幾頁的。

2. 獲取爬取的連接

待爬取的頁面

在谷歌瀏覽器中,鼠標移動到上紅框所選文字上,鼠標右鍵選擇檢查,或者ctrl+shift+i。


待獲取網頁連接

可以看到我們想要的連接在一個a標簽里面。
這里我們可以使用xpath簡單的提取出內容:

//th/a[2]/@href # 所有帖子的連接
 

3. 帖子詳情內容

我們的目的是為了看招聘內容,因此除了樓主的內容,其他的不需要看。


詳情內容

這幾個內容是我們需要的:

鏈接 //h1/a/@href #帖子鏈接,方便人工排錯,也是惟一地址
標題 //*[@id="thread_subject"]/text() # 這里主要用來存儲做標題
時間 //*[@class="authi"]/em/span/@title #時間太久的,可能已經招到人了,也有的會在帖子內發出,封貼,這里就簡單點,不想把邏輯弄的太復雜了
內容 //td[@class="t_f"]/text() #內容是我們真正想要的,如果有時間,我們可以細分,把內容里的郵箱,電話號碼單獨提取出來

二、 創建爬蟲工程

雖然是個小項目,自己手動寫寫也很快,但是為了記憶scrapy,還是選擇用scrapy框架。

> scrapy startproject job #創建工程
> scrapy genspider cnnb http://bbs.cnnb.com #生成爬蟲,名字叫cnnb
生成爬蟲

查看下目錄結構:

項目結構

可以看到在job/spiders下面有一個cnnb.py的文件了。

三、 model設置

scrapy的item是向django學習的,因此還是model的意思.
打開job/items.py文件,添加這些內容:

import scrapy

class JobItem(scrapy.Item):
    link = scrapy.Field() #帖子連接
    title = scrapy.Field() #標題
    date = scrapy.Field() #發布日期
    content = scrapy.Field() #內容

四、 爬蟲主程序

打開job/spiders/cnnb.py. 我們能看到scrapy已經為我們創建好了模板,我們的工作就是在模板上進行修改。

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


class CnnbSpider(scrapy.Spider):
    name = "cnnb"
    allowed_domains = ["http://bbs.cnnb.com"]
    start_urls = ['http://http://bbs.cnnb.com/']

    def parse(self, response):
        pass

構建爬蟲的爬取入口:

    start_urls = ['http://bbs.cnnb.com/forum.php?mod=forumdisplay&fid=37&filter=author&orderby=dateline&typeid=366&page=1']

解析內容,注意這就是scrapy框架的強大之處,我們不用關心怎么下載內容,只須要定義好從哪兒開始爬取,和解析需要的內容:

    def parse(self, response):
        # 解析帖子鏈接
        links = response.xpath("http://th/a[2]/@href")

這里我們可以使用scrapy提供的命令行工具,檢查我們的查詢條件寫的是否正確:

$ scrapy shell http://bbs.cnnb.com/forum.php?mod=forumdisplay&fid=37&filter=author&orderby=dateline&typeid=366&page=1

2018-04-23 15:30:45 [scrapy.utils.log] INFO: Scrapy 1.3.3 started (bot: job)
2018-04-23 15:30:45 [scrapy.utils.log] INFO: Overridden settings: {'BOT_NAME': 'job', 'DUPEFILTER_CLASS': 'scrapy.dupefilters.BaseDupeFilter', 'LOGSTATS_INTERVAL': 0, 'NEWSPIDER_MODULE': 'job.spiders', 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['job.spiders']} 2018-04-23 15:30:46 [scrapy.middleware] INFO: Enabled extensions:
...
[s]   fetch(req)                  Fetch a scrapy.Request and update local objects
[s]   shelp()           Shell help (print this help)
[s]   view(response)    View response in a browser
In [1]:

輸入 response.xpath("http://th/a[2]/@href")

返回結果

可以看到返回的是SelectorList類型,我們可以加上.exract()獲取數據:

查詢結果

其他幾個也是這樣測試,就不一一說明了。現在我們的文件內容應該是這樣了。

# -*- coding: utf-8 -*-
import scrapy
from items import JobItem

class CnnbSpider(scrapy.Spider):
    name = "cnnb"
    allowed_domains = ["http://bbs.cnnb.com"]
    start_urls = ['http://bbs.cnnb.com/forum.php?mod=forumdisplay&fid=37&filter=author&orderby=dateline&typeid=366&page=1']

    def parse(self, response):
        # 解析帖子鏈接
        links = response.xpath("http://th/a[2]/@href").extract()

        # 解析每一個連接的帖子內容
        for each in links[:2]:
            yield scrapy.Request(each, callback=self.parse_content)

    def parse_content(self, response):
        jobitem = JobItem()
        jobitem['link'] = response.url
        jobitem['title'] = response.xpath('//*[@id="thread_subject"]/text()').extract_first() # 這里依然可以用extract(),不過exract()返回的是列表,extract_first()返回的是字符串
        jobitem['date'] = response.xpath('//*[@class="authi"]/em/span/@title').extract_first()
        jobitem['content'] = self._get_content(response)
        yield jobitem

    def _get_content(self, response):
        content =  response.xpath('//td[@class="t_f"]//text()').extract()
        return ''.join(content).replace('\r','').replace('\n','')

五、 儲存結果

此時我們已經可以儲存結果,獲取第一頁的信息了。我們可以使用scrapy默認提供的命令:

> scrapy crawl cnnb -o cnnb.json
json結果

此時json文件已經有了,如果沒有,可以在settings.py里修改下。

ROBOTSTXT_OBEY = True #True改成False 或者注釋掉這條

可是文件內容是什么,完全看不懂呀,別急,這只scrapy的安全保護,在settings.py添加下面這條內容。

FEED_EXPORT_ENCODING = 'utf-8'

重新啟動爬蟲,再打開json看看:


utf-8格式化后json

又是可愛的中文了。

六、 下一頁

看到這兒,大家已經能爬取一頁內容了,可能有人會說,“我去,一頁我手翻也能看完了,我要的是所有頁面呀”。
這就涉及到了,怎么看下一頁?
回到網頁結構,我們看看下一頁網頁代碼是怎么樣的?


下一頁

可以看到是在a標簽里。

        #下一頁
        next_page = response.xpath('//a[@class="nxt"]/@href').extract_first()
        if next_page:
            yield scrapy.Request(next_page, callback=self.parse)

到這里我們已經能成功完成任務了。

下一步,我們將把數據存儲到數據庫,可以看Scrapy 抓取本地論壇招聘內容 (二)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容