寫的內容越來越多,因此做成一個系列,謝謝大家。我將定期更新相關內容:
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文件已經有了,如果沒有,可以在settings.py里修改下。
ROBOTSTXT_OBEY = True #True改成False 或者注釋掉這條
可是文件內容是什么,完全看不懂呀,別急,這只scrapy的安全保護,在settings.py添加下面這條內容。
FEED_EXPORT_ENCODING = '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 抓取本地論壇招聘內容 (二)