上一關,我們學習了Scrapy框架,知道了Scrapy爬蟲公司的結構和工作原理。
在Scrapy爬蟲公司里,引擎是最大的boss,統領著調度器、下載器、爬蟲和數據管道四大部門。
這四大部門都聽命于引擎,視引擎的需求為最高需求。
我們還通過實操爬取豆瓣Top250圖書的項目,熟悉了Scrapy的用法。
這一關,我會帶你實操一個更大的項目——用Scrapy爬取招聘網站的招聘信息。
你可以借此體驗一把當Scrapy爬蟲公司CEO的感覺,用代碼控制并操作整個Scrapy的運行。
那我們爬取什么招聘網站呢?在眾多招聘網站中,我挑選了職友集。這個網站可以通過索引的方式,搜索到全國上百家招聘網站的最新職位。
https://www.jobui.com/rank/company/
我們先對這個網站做初步的觀察,這樣我們才能明確項目的爬取目標。
明確目標
打開網址后,你會發現:這是職友集網站的地區企業排行榜,里面含有本月人氣企業榜、最佳口碑雇主、最多粉絲企業榜和最多評論企業榜四個榜單。
點擊【北京字節跳動科技有限公司】,會跳轉到這家公司的詳情頁面,再點擊【招聘】,就能看到這家公司正在招聘的所有崗位信息。
初步觀察后,我們可以把爬取目標定為:先爬取企業排行榜四個榜單里的公司,再接著爬取這些公司的招聘信息。
每個榜單有10家公司,四個榜單一共就是40家公司。也就是說,我們要先從企業排行榜爬取到這40家公司,再跳轉到這40家公司的招聘信息頁面,爬取到公司名稱、職位、工作地點和招聘要求。
分析過程
明確完目標,我們開始分析過程。首先,要看企業排行榜里的公司信息藏在了哪里。
企業排行榜的公司信息
請你右擊打開“檢查”工具,點擊Network,刷新頁面。點開第0個請求company/,看Response,找一下有沒有榜單的公司信息在里面。
一找,發現四個榜單的所有公司信息都在里面。說明企業排行榜的公司信息就藏在html里。
現在請你點擊Elements,點亮光標,再把鼠標移到【北京字節跳動科技有限公司】,這時就會定位到含有這家公司信息的元素上。
點擊href="/company/10375749/",會跳轉到字節跳動這家公司的詳情頁面。詳情頁面的網址是:
https://www.jobui.com/company/10375749/
你再把鼠標移到【阿里巴巴集團】,點擊href="/company/281097/",會跳轉到阿里公司的詳情頁面,頁面的網址為:
https://www.jobui.com/company/281097/
我們可以猜到:/company/+數字/應該是公司id的標識。這么一觀察,榜單上的公司詳情頁面的網址規律我們就得出來了。
那么,我們只要把元素的href屬性的值提取出來,就能構造出每家公司詳情頁面的網址。
構造公司詳情頁面的網址是為了后面能獲得詳情頁面里的招聘信息。
現在,我們來分析html的結構,看看怎樣才能把元素href屬性的值提取出來。
仔細觀察html的結構,你會發現,每個公司信息都藏在一個
-
標簽。這是一個層層嵌套的關系。
我們想拿到所有元素href屬性的值。我們當然不能直接用find_all()抓取標簽,原因也很簡單:這個頁面有太多的標簽,會抓出來很多我們不想要的信息。
一個穩妥的方案是:先抓取最外層的
-
標簽,再抓取
-
標簽里的 元素,最后提取到 元素href屬性的值。就像剝洋蔥,要從最外面的一層開始剝一樣。
這里沒有通過抓
分析到這里,我們已經知道公司詳情頁面的網址規律,和如何提取元素href屬性的值。
接下來,我們需要分析的就是,每家公司的詳情頁面。
公司詳情頁面的招聘信息
我們打開【北京字節跳動科技有限公司】的詳情頁面,點擊【招聘】。這時,網址會發生變化,多了jobs的參數。
如果你多點擊幾家公司的詳情頁面,查看招聘信息,就會知道:公司招聘信息的網址規律也是有規律的。
比如,阿里的招聘信息的網址是:
https://www.jobui.com/company/281097/jobs/
還是在字節跳動公司的招聘信息頁面,右擊打開“檢查”工具,點擊Network,刷新頁面。我們點擊第0個請求jobs/,查看Response,翻找看看里面有沒有這家公司的招聘信息。
在Response里我們找到了想要的招聘信息。這說明公司的招聘信息依舊是藏在了html里。
接下來,你應該知道要分析什么了吧。
分析的套路都是相同的,知道數據藏在html后,接著是分析html的結構,想辦法提取出我們想要的數據。
那就按照慣例點擊Elements,然后點亮光標,把鼠標移到公司名稱吧。
公司名稱藏在
不過經過我幾次的操作試驗,發現職友集這個網站間隔一段時間就會更換這個標簽的名字(可能你此時看到的標簽名不一定是
)。
為了保證一定能取到公司名稱,我們改成用id屬性(id=“companyH1”)來定位這個標簽。這樣,不管這個標簽名字如何更換,我們依舊能抓到它。
下面,再把鼠標移到崗位名稱,看看招聘的崗位信息可以怎么提取。
你會發現:每個崗位的信息都藏在一個
div class="job-desc"
的兩個
s pan
元素里。

這樣分析下來,我們想要的招聘信息,包括公司名稱、職位名稱、工作地點和職位要求,都定位清楚了。
至此,我們分析完了整個爬取過程,接下來就是代碼實現啦。
代碼實現
我們按照Scrapy正常的用法一步步來。首先,我們必須創建一個Scrapy項目。
創建項目
還記得怎么創建嗎?打開本地電腦的終端(windows:Win+R,輸入cmd;mac:command+空格,搜索“終端”),跳轉到你想要保存項目的目錄下,輸入創建Scrapy項目的命令:scrapy startproject jobui(jobui是職友集網站的英文名,在這里我們把它作為Scrapy項目的名字)。
創建好項目后,你在本地電腦的編譯器打開這個Scrapy項目,會看到如下的結構:
定義item
我們剛剛分析的時候,已經確定要爬取的數據是公司名稱、職位名稱、工作地點和招聘要求。
那么,現在請你寫出定義item的代碼(提示:要在items.py這個文件里定義item。
import scrapy
class JobuiItem(scrapy.Item):
#定義了一個繼承自scrapy.Item的JobuiItem類
company = scrapy.Field()
#定義公司名稱的數據屬性
job = scrapy.Field()
#定義職位名稱的數據屬性
base = scrapy.Field()
#定義工作地點的數據屬性
detail = scrapy.Field()
#定義招聘要求的數據屬性
創建和編寫爬蟲文件
定義好item,我們接著要做的是在spiders里創建爬蟲文件,命名為jobui_ jobs。
現在,我們可以開始在這個爬蟲文件里編寫代碼。
先導入所需的模塊:
import scrapy
import bs4
from ..items import JobuiItem
接下來,是編寫爬蟲的核心代碼。我會先帶著你理清代碼的邏輯,這樣等下你才能比較順利地理解和寫出代碼。
在前面分析過程的步驟里,我們知道要先抓取企業排行榜40家公司的id標識,比如字節跳動公司的id標識是/company/10375749/。
再利用抓取到的公司id標識構造出每家公司招聘信息的網址。比如,字節跳動公司的招聘信息網址就是https://www.jobui.com+/company/10375749/jobs/
我們需要再把每家公司招聘信息的網址封裝成requests對象。這里你可能有點不理解為什么要封裝成requests對象,我解釋一下。
如果我們不是使用Scrapy,而是使用requests庫的話,一般我們得到一個網址,需要用requests.get(),傳入網址這個參數,才能獲取到網頁的源代碼。
而在Scrapy里,獲取網頁源代碼這件事兒,會由引擎交分配給下載器去做,不需要我們自己處理。我們之所以要構造新的requests對象,是為了告訴引擎,我們新的請求需要傳入什么參數。
這樣才能讓引擎拿到的是正確requests對象,交給下載器處理。
既然構造了新的requests對象,我們就得定義與之匹配的用來處理response的新方法。這樣才能提取出我們想要的招聘信息的數據。
好啦,核心代碼的邏輯我們理清楚了。
import scrapy
import bs4
from ..items import JobuiItem
class JobuiSpider(scrapy.Spider):
#定義一個爬蟲類JobuiSpider
name='jobs'
#定義爬蟲的名字為jobs
allowed_domains=['www.jobui.com']
#定義允許爬蟲爬取網址的域名——職友集網站的域名
start_ulrs=['https://www.jobui.com/rank/company/']
#定義起始網址——職友集企業排行榜的網址
def parse(self,response):
#parse是默認處理response的方法
bs=bs4.BeautifulSoup(response.text,'html.parser')
#用BeautifulSoup解析response(企業排行榜的網頁源代碼)
ur_list=bs.find_all('ul',class_='textList flsty cfix')
#用find_all提取<'ul' class_='textList flsty cfix'>標簽
for ul in ul_list:
#遍歷ul_list
a_list = ul.find_all('a')
#用find_all提取出
第6-13行代碼:定義了爬蟲類JobuiSpider、爬蟲的名字jobs、允許爬蟲爬取的域名和起始網址。
剩下的代碼,你應該都能看懂。我們用默認的parse方法來處理response(企業排行榜的網頁源代碼);用BeautifulSoup來解析response;用find_all方法提取數據(公司id標識)。
公司id標識就是元素的href屬性的值,我們想要把它提取出來,就得先抓到所有最外層的
-
標簽,再從中抓取所有 元素。
所以這里用了兩個for循環,把元素的href屬性的值提取了出來,并成功構造了公司招聘信息的網址。
代碼寫到這里,我們已經完成了核心代碼邏輯的前兩件事:提取企業排行榜的公司id標識和構造公司招聘信息的網址。
接下來,就是構造新的requests對象和定義新的方法處理response。
繼續來完善核心代碼(請你重點看第21行代碼及之后的代碼)。
在這里插入代碼片
你應該不理解第22行代碼:yield scrapy.Request(real_url, callback=self.parse_job)的意思。我跟你解釋一下。
scrapy.Request是構造requests對象的類。real_url是我們往requests對象里傳入的每家公司招聘信息網址的參數。
callback的中文意思是回調。self.parse_job是我們新定義的parse_job方法。往requests對象里傳入callback=self.parse_job這個參數后,引擎就能知道response要前往的下一站,是parse_job()方法。
yield語句就是用來把這個構造好的requests對象傳遞給引擎。
第26-42行代碼:提取出公司名稱、職位名稱、工作地點和招聘要求這些數據,并把這些數據放進我們定義好的JobuiItem類里。
最后,用yield語句把item傳遞給引擎,整個核心代碼就編寫完啦!ヽ(???)?(???)?
存儲文件
至此,我們整個項目還差存儲數據這一步。在第6關,我們學過用csv模塊把數據存儲csv文件,用openpyxl模塊把數據存儲Excel文件。
其實,在Scrapy里,把數據存儲成csv文件和Excel文件,也有分別對應的方法。我們先說csv文件。
存儲成csv文件的方法比較簡單,只需在settings.py文件里,添加如下的代碼即可。
FEED_URI='./storage/data/%(name)s.csv'
FEED_FORMAT='CSV'
FEED_EXPORT_ENCODING='ansi'
FEED_URI是導出文件的路徑。’./storage/data/%(name)s.csv’,就是把存儲的文件放到與settings.py文件同級的storage文件夾的data子文件夾里。
FEED_FORMAT 是導出數據格式,寫CSV就能得到CSV格式。
FEED_EXPORT_ENCODING 是導出文件編碼,ansi是一種在windows上的編碼格式,你也可以把它變成utf-8用在mac電腦上。
存儲成Excel文件的方法要稍微復雜一些,我們需要先在setting.py里設置啟用ITEM_PIPELINES,設置方法如下:
#需要修改`ITEM_PIPELINES`的設置代碼:
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
#ITEM_PIPELINES = {
# 'jobuitest.pipelines.JobuitestPipeline': 300,
# }
只要取消ITEM_PIPELINES的注釋(刪掉#)即可。
#取消`ITEM_PIPELINES`的注釋后:
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'jobuitest.pipelines.JobuitestPipeline': 300,
}
接著,我們就可以去編輯pipelines.py文件。存儲為Excel文件,我們依舊是用openpyxl模塊來實現,代碼如下,注意閱讀注釋:
import openpyxl
class JobuiPipeline(object):
#定義一個JobuiPipeline類,負責處理item
def __init__(self):
#初始化函數 當類實例化時這個方法會自啟動
self.wb =openpyxl.Workbook()
#創建工作薄
self.ws = self.wb.active
#定位活動表
self.ws.append(['公司', '職位', '地址', '招聘信息'])
#用append函數往表格添加表頭
def process_item(self, item, spider):
#process_item是默認的處理item的方法,就像parse是默認處理response的方法
line = [item['company'], item['position'], item['address'], item['detail']]
#把公司名稱、職位名稱、工作地點和招聘要求都寫成列表的形式,賦值給line
self.ws.append(line)
#用append函數把公司名稱、職位名稱、工作地點和招聘要求的數據都添加進表格
return item
#將item丟回給引擎,如果后面還有這個item需要經過的itempipeline,引擎會自己調度
def close_spider(self, spider):
#close_spider是當爬蟲結束運行時,這個方法就會執行
self.wb.save('./jobui.xlsx')
#保存文件
self.wb.close()
#關閉文件
修改設置
在最后,我們還要再修改Scrapy中settings.py文件里的默認設置:添加請求頭,以及把
ROBOTSTXT_OBEY=True
改成
ROBOTSTXT_OBEY=False
。
#需要修改的默認設置:
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'douban (+http://www.yourdomain.com)'
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
還有一處默認設置我們需要修改,代碼如下:
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 0
我們需要取消DOWNLOAD_DELAY = 0這行的注釋(刪掉#)。DOWNLOAD_DELAY翻譯成中文是下載延遲的意思,這行代碼可以控制爬蟲的速度。因為這個項目的爬取速度不宜過快,我們要把下載延遲的時間改成0.5秒。
改好后的代碼如下:
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.5
修改完設置,我們已經可以運行代碼。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
