首頁  >  文章  >  後端開發  >  爬蟲框架Scrapy實戰之批量抓取招募訊息

爬蟲框架Scrapy實戰之批量抓取招募訊息

高洛峰
高洛峰原創
2016-10-17 13:49:341029瀏覽

所謂網路爬蟲,就是一個在網路上到處或定向抓取資料的程序,當然,這種說法不夠專業,更專業的描述就是,抓取特定網站網頁的HTML資料。不過由於一個網站的網頁很多,而我們又不可能事先知道所有網頁的URL位址,所以,如何保證我們抓取到了網站的所有HTML頁面就是一個有待考究的問題了。一般的方法是,定義一個入口頁面,然後一般一個頁面會有其他頁面的URL,於是從當前頁面獲取到這些URL加入到爬蟲的抓取隊列中,然後進入到新頁面後再遞歸的進行上述的操作,其實說來就跟深度遍歷或廣度遍歷一樣。

Scrapy是一個基於Twisted,純Python實現的爬蟲框架,用戶只需要定制開發幾個模組就可以輕鬆的實現一個爬蟲,用來抓取網頁內容以及各種圖片,非常之方便~

Scrapy 使用Twisted這個非同步網路庫來處理網路通訊,架構清晰,並且包含了各種中間件接口,可以靈活的完成各種需求。整體架構如下圖:

爬蟲框架Scrapy實戰之批量抓取招募訊息

綠線是資料流向,首先從初始URL 開始,Scheduler 會將其交給Downloader 進行下載,下載之後會交給Spider 進行分析,Spider分析出來的結果有兩種:一種是需要進一步抓取的鏈接,例如之前分析的“下一頁”的鏈接,這些東西會被傳回Scheduler ;另一種是需要保存的數據,它們則被送到Item Pipeline 那裡,那是對資料進行後製(詳細分析、過濾、儲存等)的地方。另外,在資料流動的通道裡還可以安裝各種中間件,進行必要的處理。


我假定你已經安裝了Scrapy。假如你沒有安裝,你可以參考這篇文章。

在本文中,我們將學會如何使用Scrapy建立一個爬蟲程序,並爬取指定網站上的內容

1. 創建一個新的Scrapy Project

2. 定義你需要從網頁中提取的元素Item

3.實作一個Spider類,透過介面完成爬取URL和提取Item的功能

4. 實作一個Item PipeLine類,完成Item的儲存功能

我將會用騰訊招募官網作為例子。

Github原始碼:https://github.com/maxliaops/scrapy-itzhaopin

爬蟲框架Scrapy實戰之批量抓取招募訊息

目標:抓取騰訊招募官網職位招募資訊並儲存為JSON格式。

新建工程

首先,為我們的爬蟲新建一個工程,首先進入一個目錄(任一我們用來保存程式碼的目錄),執行:

scrapy startprojectitzhaopin

scrapy startprojectitzhaopin

itz

itz這個指令會在目前目錄下建立一個新目錄itzhaopin,結構如下:

.

├── itzhaopin

│   ├── itzhaopin

⠂ ⠎ ├── items .py

│   │   ├── pipelines.py

│   │   ├── settings.py

└── __init__.py

│   └── scrapy.cfg

 

scrapy.cfg: 專案設定檔

items.py: 需要提取的資料結構定義檔

pipelines.py:管道定義,用來對items裡面提取的資料做進一步處理,如保存等

ett .py: 爬蟲設定檔

spiders: 放置spider的目錄


定義Item

在items.py裡面定義我們要抓取的資料:

from scrapy.item import Item, Field
class TencentItem(Item):
    name = Field()                # 职位名称
    catalog = Field()             # 职位类别
    workLocation = Field()        # 工作地点
    recruitNumber = Field()       # 招聘人数
    detailLink = Field()          # 职位详情页链接
    publishTime = Field()         # 发布时间
contrib.spiders.CrawlSpider的Python類,有三個必需的定義的成員

name: 名字,這個spider的標識

start_urls:一個url列表,spider從這些網頁開始抓取

parse():一個方法,當start_urls裡面的網頁抓取下來之後需要呼叫這個方法解析網頁內容,同時需要返回下一個需要抓取的網頁,或者返回items列表

所以在spiders目錄下新建一個spider,tencent_spider.py:

import re
import json
from scrapy.selector import Selector
try:
    from scrapy.spider import Spider
except:
    from scrapy.spider import BaseSpider as Spider
from scrapy.utils.response import get_base_url
from scrapy.utils.url import urljoin_rfc
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor as sle
from itzhaopin.items import *
from itzhaopin.misc.log import *
class TencentSpider(CrawlSpider):
    name = "tencent"
    allowed_domains = ["tencent.com"]
    start_urls = [
        "http://hr.tencent.com/position.php"
    ]
    rules = [ # 定义爬取URL的规则
        Rule(sle(allow=("/position.php\?&start=\d{,4}#a")), follow=True, callback='parse_item')
    ]
    def parse_item(self, response): # 提取数据到Items里面,主要用到XPath和CSS选择器提取网页数据
        items = []
        sel = Selector(response)
        base_url = get_base_url(response)
        sites_even = sel.css('table.tablelist tr.even')
        for site in sites_even:
            item = TencentItem()
            item['name'] = site.css('.l.square a').xpath('text()').extract()
            relative_url = site.css('.l.square a').xpath('@href').extract()[0]
            item['detailLink'] = urljoin_rfc(base_url, relative_url)
            item['catalog'] = site.css('tr > td:nth-child(2)::text').extract()
            item['workLocation'] = site.css('tr > td:nth-child(4)::text').extract()
            item['recruitNumber'] = site.css('tr > td:nth-child(3)::text').extract()
            item['publishTime'] = site.css('tr > td:nth-child(5)::text').extract()
            items.append(item)
            #print repr(item).decode("unicode-escape") + '\n'
        sites_odd = sel.css('table.tablelist tr.odd')
        for site in sites_odd:
            item = TencentItem()
            item['name'] = site.css('.l.square a').xpath('text()').extract()
            relative_url = site.css('.l.square a').xpath('@href').extract()[0]
            item['detailLink'] = urljoin_rfc(base_url, relative_url)
            item['catalog'] = site.css('tr > td:nth-child(2)::text').extract()
            item['workLocation'] = site.css('tr > td:nth-child(4)::text').extract()
            item['recruitNumber'] = site.css('tr > td:nth-child(3)::text').extract()
            item['publishTime'] = site.css('tr > td:nth-child(5)::text').extract()
            items.append(item)
            #print repr(item).decode("unicode-escape") + '\n'
        info('parsed ' + str(response))
        return items
    def _process_request(self, request):
        info('process ' + str(request))
        return request

實作PipeLine 

PipeLine用來對Spider回傳的Item清單進行儲存操作,可以寫入檔案、或資料庫等。

PipeLine只有一個需要實現的方法:process_item,例如我們將Item保存到JSON格式檔案中:

pipelines.py

from scrapy import signals
import json
import codecs
class JsonWithEncodingTencentPipeline(object):
    def __init__(self):
        self.file = codecs.open('tencent.json', 'w', encoding='utf-8')
    def process_item(self, item, spider):
        line = json.dumps(dict(item), ensure_ascii=False) + "\n"
        self.file.write(line)
        return item
    def spider_closed(self, spider):
        self.file.close(
)

到現在,我們就完成了一個基本的爬蟲的實現,可以輸入下面的命令來啟動這個Spider:

scrapy crawl tencent

爬蟲運行結束後,在當前目錄下將會生成一個名為tencent.json的文件,其中以JSON格式保存了職位招聘信息。

部分內容如下:

{"recruitNumber": ["1"], "name": ["SD5-資深手遊規劃(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id =15626&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"], "catalog": ["產品/專案類別"], "workLocation": ["深圳"]}

{ "recruitNumber": ["1"], "name": ["TEG13-後台開發工程師(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15666&keywords= &tid=0&lid=0", "publishTime": ["2014-04-25"], "catalog": ["技術類"], "workLocation": ["深圳"]}

{"recruitNumber": [ "2"], "name": ["TEG12-資料中心資深經理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15698&keywords=&tid=0&lid= 0", "publishTime": ["2014-04-25"], "catalog": ["技術類"], "workLocation": ["深圳"]}

{"recruitNumber": ["1"] , "name": ["GY1-微信支付品牌規劃經理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15710&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"], "catalog": ["市場類"], "workLocation": ["深圳"]}

{"recruitNumber": ["2"], "name ": ["SNG06-後台開發工程師(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15499&keywords=&tid=0&lid=0", "publishTime": [ "2014-04-25"], "catalog": ["技術類"], "workLocation": ["深圳"]}

{"recruitNumber": ["2"], "name": ["OMG01 -騰訊時尚影片策劃編輯(北京)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15694&keywords=&tid=0&lid=0", "publishTime": ["2014- 04-25"], "catalog": ["內容編輯類"], "workLocation": ["北京"]}

{"recruitNumber": ["1"], "name": ["HY08-QT用戶端Windows開發工程師(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=11378&keywords=&tid=0&lid=0", "publishTime": ["2014-04 -25"], "catalog": ["技術類"], "workLocation": ["深圳"]}

{"recruitNumber": ["5"], "name": ["HY1-手機遊戲測試經理(上海)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=15607&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"] , "catalog": ["技術類"], "workLocation": ["上海"]}

{"recruitNumber": ["1"], "name": ["HY6-網咖平台資深產品經理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=10974&keywords=&tid=0&lid=0", "publishTime": ["2014-04-25"], "catalog ": ["產品/專案類"], "workLocation": ["深圳"]}

{"recruitNumber": ["4"], "name": ["TEG14-雲端儲存研發工程師(深圳)" ], "detailLink": "http://hr.tencent.com/position_detail.php?id=15168&keywords=&tid=0&lid=0", "publishTime": ["2014-04-24"], "catalog": ["技術類"], "workLocation": ["深圳"]}

{"recruitNumber": ["1"], "name": ["CB-薪資經理(深圳)"], "detailLink": "http://hr.tencent.com/position_detail.php?id=2309&keywords=&tid=0&lid=0", "publishTime": ["2013-11-28"], "catalog": ["職能類別"] , "workLocation": ["深圳"]}


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn