#1.Scrapy
- Scrapy介紹
-
純python開發實現的一個爬蟲框架
-
包含爬取資料、提取結構性資料、應用框架
-
底層通過Twisted非同步網路框架處理網路通訊
-
可擴充套件、高效能、多執行緒、分散式爬蟲框架
-
###scrapy體系結構
- Scrapy Engine(引擎元件):
負責Spider、ItemPipeline、Downloader、Scheduler的工作排程、資訊通訊、資料傳遞等工作
- Scheduler(排程元件):
負責接收引擎傳遞過來的請求,按照具體規則新增佇列處理,最終返回給引擎
- Downloader(下載元件):
負責下載引擎傳遞過來的所有Request請求,最終伺服器的響應資料返回給引擎元件
- Spider(爬蟲):
處理所有Response響應,分析提取Item資料 如果資料中有二次請求,繼續交給引擎元件
- ItemPipeline(管道):
負責[分析、過濾、儲存]處理由Spiders獲取到的Item資料
###常用命令
- startproject:建立一個新專案
- genspider:根據模板生成一個新爬蟲
- crawl:執行爬蟲
- shell:啟動互動式抓取控制檯 #2.安裝和配置 我的系統是 Win7,所以這裡只詳細介紹Windows 平臺的安裝,首先,你要有Python,我用的是2.7.7版本和3.5的版本共存。
- 官網文件:doc.scrapy.org/en/latest/i…
- 中文文件
說點題外話,其實並不是所有的官網文件都很難看懂,每次進入英文的網站,你覺得很難只是你對英文網站反射性的牴觸而已,慢慢的讀下去,不懂的可以查有道詞典,慢慢的你看到一些全是英文網站會發現其實沒有想象的那麼難了。言歸正傳,我們簡單介紹下ubuntu和mac os下的Scrapy安裝
- ubuntu安裝
apt-get install python-dev python-pip libxml12-dev libxstl1-dev
zlig1g-dev libssl-dev
pip install scrapy
複製程式碼
- mac os安裝
官方:建議不要使用自帶的python環境
安裝:參考官方文件
複製程式碼
####1.windows安裝 在命令視窗輸入:
pip install scrapy
複製程式碼
安裝完畢之後,輸入 scrapy
- 同時需要安裝win32py,提供win32api,下載地址:sourceforge.net/projects/py…
- 下載完成以後,這是一個exe檔案,直接雙擊安裝就可以了。點選下一步。
第二步,你會看到你的python安裝目錄,如果沒有檢測到你的python安裝目錄,八成你現在的pywin32版本是不對的,重新下載。點選下一步看到這個介面,說明你安裝完成
- 在python中,引入win32com,測試一下,如果沒有錯誤提示,說明安裝成功
#3.安裝過程常見錯誤
- 如果是這個錯誤,這是pip版本的問題,需要更新pip的版本
在命令視窗輸入:pip install -U pip 複製程式碼
- 如果出現的錯誤是
ReadTimeout
,則是超時的原因,重新安裝一遍就行。 其他錯誤參考網站:python+scrapy安裝教程,一步步來一遍看到底是哪一步出錯。
#4.程式碼操作 - 建立一個Scrapy專案 ###流程:
- 建立一個Scrapy專案;
- 定義提取的Item;
- 編寫爬取網站的 spider 並提取 Item;
- 編寫 Item Pipeline 來儲存提取到的Item(即資料)。 ###1.爬取智聯招聘相關python搜尋頁資料 分析:
(1)分析智聯招聘網址構成;
(2)獲取網頁結構,找出對應的Xpath;
(3)寫入html文件。
- 分析過程:
# 當前頁面中所有的崗位描述
//div[@id="newlist_list_div"]//table
# 招聘崗位
//div[@id="newlist_list_div"]//table//td[1]//a
# 反饋概率
//div[@id="newlist_list_div"]//table//td[2]//span
# 釋出公司
//div[@id="newlist_list_div"]//table//td[3]//a/text()
# 崗位月薪
//div[@id="newlist_list_div"]//table//td[4]/text()
複製程式碼
- 建立第一個Scrapy框架第一個專案
- 在命令視窗輸入
scrapy startproject firPro
複製程式碼
會建立一個firPro
的資料夾,結構如下:
|-- firProl/ # 專案資料夾
|-- scrapy.cfg # 專案釋出配置
|-- spiders/ # 專案模組儲存了實際的爬蟲程式碼
|-- __init__.py # 模組描述檔案
|-- items.py # 定義了待抓取域的模型
|-- pipelines.py # 專案pipelines定義檔案
|--settings.py # 專案全域性配置,定義了一些設定,如使用者代理、爬取延時等。
|-- spiders/ # 爬蟲模組<開發>
|-- __init__.py # 模組描述檔案
複製程式碼
####1.items.py
中程式碼
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class FirproItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
#定義儲存崗位的名稱的欄位
name = scrapy.Field()
#反饋概率
percent = scrapy.Field()
#釋出公司
company = scrapy.Field()
#崗位月薪
salary = scrapy.Field()
#工作地點
position = scrapy.Field()
複製程式碼
####2.在spiders建立fir_spider.py
檔案
# -*- coding: utf-8 -*-
import scrapy
#自定義的爬蟲程式處理類,要繼承scrapy模組的spider型別
class Firspider(scrapy.Spider):
#定義爬蟲程式的名稱,用於程式的啟動使用
name = 'firspider'
#定義爬蟲程式執行的作用域--域名
allow_domains = 'http://sou.zhaopin.com'
#定義爬蟲程式真實爬取url地址的列表/原組
start_urls = ('http://sou.zhaopin.com/jobs/searchresult.ashx?jl=%E4%B8%8A%E6%B5%B7&kw=python&sm=0&p=1&source=0',)
#定義爬蟲獲取到的響應資料處理類
#response就是爬取程式獲取的資料
def parse(self,response):
with open(u'智聯.html','w') as f:
f.write(response.body)
複製程式碼
####3.在當前資料夾進入命令視窗 輸入命令執行:
#這裡執行的名字是fir_spider.py中定義爬蟲程式的名稱
scrapy crawl firspider
複製程式碼
####4.儲存我們想要的資料
# -*- coding: utf-8 -*-
import scrapy
from firPro.items import FirproItem
#自定義的爬蟲程式處理類,要繼承scrapy模組的spider型別
class Firspider(scrapy.Spider):
#定義爬蟲程式的名稱,用於程式的啟動使用
name = 'firspider'
#定義爬蟲程式執行的作用域--域名
allow_domains = 'http://sou.zhaopin.com'
#定義爬蟲程式真實爬取url地址的列表/原組
start_urls = ('http://sou.zhaopin.com/jobs/searchresult.ashx?jl=%E4%B8%8A%E6%B5%B7&kw=python&sm=0&p=1&source=0',)
#定義爬蟲獲取到的響應資料處理類
#response就是爬取程式獲取的資料
# def parse(self,response):
# with open(u'智聯.html','w') as f:
# f.write(response.body)
def parse(self, response):
print (response.body)
#獲取所匹配的崗位
job_list= response.xpath('//div[@id="newlist_list_div"]//table')
#用於存放需要的崗位資料
job_lists = []
for job in job_list:
#建立一個Item物件,用於存放匹配的目標資料
item = FirproItem()
#想要顯示全,就需要extract()方法,轉換成字串輸出
item["name"] = job.xpath(".//td[1]//a/text()[1]").extract()
item["percent"] = job.xpath(".//td[2]//span")
item["company"] = job.xpath(".//td[3]//a/text()")
item["salary"] = job.xpath(".//td[4]/text()")
item["position"] = job.xpath(".//td[5]/text()")
#儲存資料
job_lists.append(item)
#將資料提交給模組pipelines處理
yield item
複製程式碼
同時settings.py
中需偽裝請求頭
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
}
#把ITEM_PIPELINES的註釋取消
ITEM_PIPELINES = {
'firPro.pipelines.FirproPipeline': 300,
}
複製程式碼
- settings.py介紹
-
**ROBOTSTXT_OBEY = True:**是否遵守robots.txt
-
**CONCURRENT_REQUESTS = 16:**開啟執行緒數量,預設16
-
**AUTOTHROTTLE_START_DELAY = 3:**開始下載時限速並延遲時間
-
**AUTOTHROTTLE_MAX_DELAY = 60:**高併發請求時最大延遲時間
-
BOT_NAME:自動生成的內容,根名字;
-
SPIDER_MODULES:自動生成的內容;
-
NEWSPIDER_MODULE:自動生成的內容;
-
ROBOTSTXT_OBEY:自動生成的內容,是否遵守robots.txt規則,這裡選擇不遵守;
-
ITEM_PIPELINES:定義item的pipeline;
-
IMAGES_STORE:圖片儲存的根路徑;
-
COOKIES_ENABLED:Cookie使能,這裡禁止Cookie;
-
DOWNLOAD_DELAY:下載延時,預設為3s。
-
####這只是簡單的爬蟲,接下來我們儲存我們想要的資料
- items.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class FirproItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
#定義儲存崗位的名稱的欄位
name = scrapy.Field()
#反饋概率
percent = scrapy.Field()
#釋出公司
company = scrapy.Field()
#崗位月薪
salary = scrapy.Field()
#工作地點
position = scrapy.Field()
複製程式碼
- pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
class FirproPipeline(object):
def __init__(self):
self.file=open('zhilian.json','w')
def process_item(self, item, spider):
text = json.dumps(dict(item),ensure_ascii=False)
self.file.write(text.encode('utf-8'))
print '-----------------'
def close_spider(self,spider):
self.file.close()
#return item
複製程式碼
- fir_spider.py
# -*- coding: utf-8 -*-
import scrapy
from firPro.items import FirproItem
import re
#自定義的爬蟲程式處理類,要繼承scrapy模組的spider型別
class Firspider(scrapy.Spider):
#定義正則匹配,把匹配到的資料進行替換
reg = re.compile('\s*')
#定義爬蟲程式的名稱,用於程式的啟動使用
name = 'firspider'
#定義爬蟲程式執行的作用域--域名
allow_domains = 'http://sou.zhaopin.com'
#定義爬蟲程式真實爬取url地址的列表/原組
url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?jl=%E4%B8%8A%E6%B5%B7&kw=python&sm=0&source=0&sg=b8e8fb4080fa47afa69cd683dfbfccf9&p='
p = 1
start_urls = [url + str(p)]
def parse(self, response):
# print (response.body)
#獲取所匹配的崗位
job_list= response.xpath('//div[@id="newlist_list_div"]//table')[2:]
for job in job_list:
#建立一個Item物件,用於存放匹配的目標資料
item = FirproItem()
name =job.xpath(".//tr[1]//td[1]//a")
# name = self.reg.sub('', job.xpath(".//td[1]//a/text()[1]").extract())
item["name"] = self.reg.sub('',name.xpath("string(.)").extract()[0])
item["percent"] = job.xpath(".//td[2]//span[1]/text()").extract()
item["company"] = job.xpath(".//td[3]//a/text()").extract()
item["salary"] = job.xpath(".//td[4]/text()").extract()
item["position"] = job.xpath(".//td[5]/text()").extract()
# 將資料提交給模組pipelines處理
yield item
if self.p<=10:
self.p+=1
yield scrapy.Request(self.url + str(self.p),callback=self.parse)
複製程式碼
同時settings.py
中需偽裝請求頭
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
}
#把ITEM_PIPELINES的註釋取消
ITEM_PIPELINES = {
'firPro.pipelines.FirproPipeline': 300,
}
複製程式碼
###2.爬取中華英才網招聘相關python搜尋頁資料
- items.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class ZhycItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 定義需要封裝的欄位
name = scrapy.Field()
publish = scrapy.Field()
company = scrapy.Field()
require = scrapy.Field()
salary = scrapy.Field()
desc = scrapy.Field()
複製程式碼
- pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
class ZhycPipeline(object):
def __init__(self):
self.file = open("zhonghuayingcai.json", "w")
def process_item(self, item, spider):
text = json.dumps(dict(item), ensure_ascii=False)
self.file.write(text.encode("utf-8"))
print "*****************************************"
#return item
def close_spider(self, spider):
self.file.close()
複製程式碼
- zhycspider.py
# -*- coding: utf-8 -*-
import scrapy
import re
from zhyc.items import ZhycItem
class ZhycspiderSpider(scrapy.Spider):
reg = re.compile("\s*")
name = 'zhycspider'
allowed_domains = ['www.chinahr.com']
url = "http://www.chinahr.com/sou/?orderField=relate&keyword=python&city=36,400&page="
page = 1
start_urls = [url + str(page)]
def parse(self, response):
job_list_xpath = response.xpath('//div[@class="jobList"]')
for jobitem in job_list_xpath:
item = ZhycItem()
name = jobitem.xpath(".//li[1]//span[1]//a")
item["name"] = self.reg.sub("", name.xpath("string(.)").extract()[0])
item["publish"] = self.reg.sub("", jobitem.xpath(".//li[1]//span[2]/text()").extract()[0])
item["company"] = self.reg.sub("", jobitem.xpath(".//li[1]//span[3]//a/text()").extract()[0])
item["require"] = self.reg.sub("", jobitem.xpath(".//li[2]//span[1]//text()").extract()[0])
item["salary"] = self.reg.sub("", jobitem.xpath(".//li[2]//span[2]//text()").extract()[0])
desc = jobitem.xpath(".//li[2]//span[3]")
item["desc"] = self.reg.sub("", desc.xpath("string(.)").extract()[0])
#print name, publish, company, require, salary, desc
#job_list.append(item)
yield item
if self.page <= 10:
self.page += 1
yield scrapy.Request(self.url + str(self.page), callback=self.parse)
#return job_list
複製程式碼
同時settings.py
中需偽裝請求頭
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
}
#把ITEM_PIPELINES的註釋取消
ITEM_PIPELINES = {
'firPro.pipelines.FirproPipeline': 300,
}
複製程式碼
- 爬取資料檔案
zhonghuayingcai.json
{
"salary": "8000-15000",
"name": "python測試工程師",
"company": "Fonrich",
"publish": "今天",
"require": "[上海市/閔行]應屆生/本科",
"desc": "電子/半導體/積體電路|民營/私企|51-100人"
}{
"salary": "7000-10000",
"name": "風險軟體工程師(Python方向)",
"company": "中銀消費金融有限公司",
"publish": "今天",
"require": "[上海市/黃浦]2年/本科",
"desc": "證券|民營/私企|101-300人"
}{
"salary": "8000-15000",
"name": "Python爬蟲開發工程師",
"company": "維賽特財經",
"publish": "今天",
"require": "[上海市/虹口]1年/大專",
"desc": "計算機軟體|民營/私企|101-300人"
}{
"salary": "8000-16000",
"name": "python爬蟲開發工程師",
"company": "上海時來",
"publish": "今天",
"require": "[上海市/長寧]應屆生/大專",
"desc": "資料服務|民營/私企|21-50人"
}{
"salary": "3000-6000",
"name": "Python講師-上海",
"company": "伊屋裝飾",
"publish": "8-11",
"require": "[上海市/黃浦]2年/大專",
"desc": "移動網際網路|民營/私企|20人以下"
}{
"salary": "6000-8000",
"name": "python開發工程師",
"company": "華住酒店管理有限公司",
"publish": "7-27",
"require": "[上海市/閔行]應屆生/本科",
"desc": "酒店|外商獨資|500人以上"
}{
"salary": "15000-25000",
"name": "赴日Python工程師",
"company": "SunWell",
"publish": "昨天",
"require": "[海外/海外/]4年/本科",
"desc": "人才服務|民營/私企|101-300人"
}
.........
.........
複製程式碼
#5.Scrapy框架進階 - 深度爬蟲 ###爬取智聯python招聘崗位
- items.py
# -*- coding: utf-8 -*-
import scrapy
class ZlItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
#崗位名稱
name = scrapy.Field()
#反饋率
percent = scrapy.Field()
#公司名稱
company = scrapy.Field()
#職位月薪
salary = scrapy.Field()
#工作地點
position = scrapy.Field()
複製程式碼
- pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
class ZlPipeline(object):
def __init__(self):
self.file = open("sdzp.json", "w")
def process_item(self, item, spider):
text = json.dumps(dict(item), ensure_ascii=False)
self.file.write(text.encode("utf-8"))
#return item
def close_spider(self, spider):
self.file.close()
複製程式碼
- zlzp.py
# -*- coding: utf-8 -*-
from scrapy.spiders import CrawlSpider,Rule
from scrapy.linkextractors import LinkExtractor
from zl.items import ZlItem
class ZlzpSpider(CrawlSpider):
name = 'sdzpspider'
allowed_domains = ['zhaopin.com']
start_urls = ['http://sou.zhaopin.com/jobs/searchresult.ashx?jl=%e4%b8%8a%e6%b5%b7&kw=python&sm=0&source=0&sg=936e2219abfb4f07a17009a930d54a37&p=1']
#定義超連結的提取規則
page_link = LinkExtractor(allow=('&sg=936e2219abfb4f07a17009a930d54a37&p=\d+'))
#定義爬蟲爬取資料的規則
rules=[
Rule(page_link,callback='parse_content',follow=True)
]
#定義處理函式
def parse_content(self, response):
#獲取整個我們需要的資料區域
job_list = response.xpath('//div[@id="newlist_list_content_table"]//table//tr[1]')
for job in job_list:
#定義一個item,用於存放目標資料
item = ZlItem()
name = job.xpath(".//td[1]//a")
if len(name)>0:
item['name'] = name.xpath('string(.)').extract()[0]
percent = job.xpath('.//td[2]//span/text()')
if len(percent)>0:
item['percent']=percent.extract()[0]
company = job.xpath(".//td[3]//a[1]/text()")
if len(company) > 0:
item["company"] = company.extract()[0]
salary = job.xpath(".//td[4]/text()")
if len(salary) > 0:
item["salary"] = salary.extract()[0]
position = job.xpath(".//td[5]/text()")
if len(position) > 0:
item["position"] = position.extract()[0]
yield item
複製程式碼
- 爬取結果顯示:
{}{
"salary": "15000-25000",
"position": "上海",
"company": "Aon Hewitt 怡安翰威特",
"name": "Senior Web Developer (Python)"
}{}{}{
"salary": "20001-30000",
"position": "上海",
"company": "上海英方軟體股份有限公司",
"name": "PHP/Python資深研發工程師"
}{
"salary": "10000-20000",
"position": "上海",
"company": "上海英方軟體股份有限公司",
"name": "PHP/Python高階研發工程師:"
}{
"salary": "15000-30000",
"position": "上海-長寧區",
"company": "攜程計算機技術(上海)有限公司",
"name": "大資料產品開發"
}{
"salary": "面議",
"position": "上海",
"company": "Michelin China 米其林中國",
"name": "DevOps Expert"
}{
"salary": "10001-15000",
"position": "上海",
"company": "中興通訊股份有限公司",
"name": "高階軟體工程師J11015"
}{
"salary": "10000-20000",
"position": "上海",
"company": "上海微創軟體股份有限公司",
"name": "高階系統運維工程師(赴迪卡儂)"
}{
"salary": "10000-15000",
"position": "上海-浦東新區",
"company": "北京尚學堂科技有限公司",
"name": "Python講師(Web方向)"
}{}{
"salary": "30000-50000",
"position": "上海",
"company": "上海復星高科技(集團)有限公司",
"name": "系統架構負責人"
}{
"salary": "面議",
"position": "上海-長寧區",
"company": "美團點評",
"name": "前端開發工程師"
}{
"salary": "12000-18000",
"position": "上海",
"company": "上海微創軟體股份有限公司",
"name": "Web前端工程師"
}{
"salary": "10000-13000",
"position": "上海",
"company": "上海微創軟體股份有限公司",
"name": "測試工程師(Test Engineer)(赴諾亞財富)"
}{
"salary": "10000-20000",
"position": "上海-浦東新區",
"company": "上海洞識資訊科技有限公司",
"name": "高階python研發人員"
}{
"salary": "6001-8000",
"position": "上海-徐彙區",
"company": "上海域鳴網路科技有限公司",
"name": "Python軟體開發"
}{
"salary": "15000-25000",
"position": "上海-浦東新區",
"company": "中移德電網路科技有限公司",
"percent": "62%",
"name": "大資料架構師"
}{
"salary": "18000-22000",
"position": "上海-浦東新區",
"company": "北京中亦安圖科技股份有限公司",
"name": "大資料開發工程師"
}
......
......
複製程式碼