1.前提
1.1 使用Mac OS系統(tǒng)
1.2 Python3.x版本
1.3 因?yàn)閙ac系統(tǒng)自帶python2.7,因此必須在終端將版本修改為python3.x版本
終端執(zhí)行:
$sudo vim ~/.bash_profile
在bash_profile文件中增加下面的語句,需要安裝python3時(shí)的路徑:
alias python='/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6’
終端執(zhí)行,使之生效:
$source ~/.bash_profile
2.安裝Scrapy
Python3.6.5安裝包中默認(rèn)帶有pip3命令,直接使用即可。
$pip3 install scrapy
注意:如果使用了
pip install scrapy,則安裝的scrapy將會默認(rèn)搜索python2.7相關(guān)文件。這會在我們運(yùn)行測試的時(shí)候報(bào)錯(cuò),因?yàn)槲覀兯械恼Z法和scrapy都是基于python3.x的!
終端應(yīng)該輸入以下內(nèi)容:
$pip3 install scrapy
Collecting scrapy
Downloading https://files.pythonhosted.org/packages/5d/12/a6197eaf97385e96fd8ec56627749a6229a9b3178ad73866a0b1fb377379/Scrapy-1.5.1-py2.py3-none-any.whl (249kB)
100% |████████████████████████████████| 256kB 600kB/s
Collecting pyOpenSSL (from scrapy)
Downloading https://files.pythonhosted.org/packages/96/af/9d29e6bd40823061aea2e0574ccb2fcf72bfd6130ce53d32773ec375458c/pyOpenSSL-18.0.0-py2.py3-none-any.whl (53kB)
100% |████████████████████████████████| 61kB 17.5MB/s
Collecting cssselect>=0.9 (from scrapy)
Downloading https://files.pythonhosted.org/packages/7b/44/25b7283e50585f0b4156960691d951b05d061abf4a714078393e51929b30/cssselect-1.0.3-py2.py3-none-any.whl
Collecting service-identity (from scrapy)
.
.
.
Successfully installed Automat-0.7.0 PyDispatcher-2.0.5 PyHamcrest-1.9.0 Twisted-18.9.0 asn1crypto-0.24.0 attrs-18.2.0 cffi-1.11.5 constantly-15.1.0 cryptography-2.3.1 cssselect-1.0.3 enum34-1.1.6 functools32-3.2.3.post2 hyperlink-18.0.0 idna-2.7 incremental-17.5.0 ipaddress-1.0.22 lxml-4.2.5 parsel-1.5.0 pyOpenSSL-18.0.0 pyasn1-0.4.4 pyasn1-modules-0.2.2 pycparser-2.19 queuelib-1.5.0 scrapy-1.5.1 service-identity-17.0.0 six-1.11.0 w3lib-1.19.0 zope.interface-4.5.0
默認(rèn)同時(shí)安裝了幾個(gè)Scrapy需要依賴的包。
3.查看Scrapy
$Scrapy version
Scrapy 1.5.1
這里安裝的是1.5.1版本
which Scrapy
/Library/Frameworks/Python.framework/Versions/3.6/bin/scrapy
這是安裝的路徑。
如果使用的是
pip install scrapy,則scrapy的路徑為/usr/local/bin/scrapy,默認(rèn)會查找python2.7版本的包,使我們的測試失敗。因?yàn)槲覀冞@里使用python3,因此這點(diǎn)需要特別注意。
4.創(chuàng)建Scrapy項(xiàng)目
在桌面創(chuàng)建了一個(gè)Demo工程
$cd Desktop
$scrapy startproject Demo
scrapy startproject:創(chuàng)建一個(gè)scrapy項(xiàng)目。
以下是項(xiàng)目的目錄結(jié)構(gòu):
Demo/
scrapy.cfg
Demo/
__init__.py
items.py
pipelines.py
settings.py
middlewares.py
spiders/
__init__.py
......
5.編寫代碼
使用Scrapy抓取一個(gè)網(wǎng)站需要四個(gè)步驟:
- 創(chuàng)建一個(gè)Scrapy項(xiàng)目
- 定義Item容器
- 編寫爬蟲
- 存儲內(nèi)容
5.1 設(shè)置抓取網(wǎng)站并建模
這里我們采用http://www.n#網(wǎng)站的站點(diǎn)資訊資源:

我們需要抓取的是該板塊的
標(biāo)題和鏈接。
在項(xiàng)目中,我們在items.py文件中建立相應(yīng)的字段:
import scrapy
class DemoItem(scrapy.Item):
#define the fields for you item here like:
#name = scrapy.Field()
title = scrapy.Field() #抓取的標(biāo)題
link = scrapy.Field() #抓取的鏈接
5.2 編寫爬蟲
在項(xiàng)目的Spider目錄中,創(chuàng)建名為DemoSprider.py的文件,編寫爬蟲代碼:
import scrapy
class DemoSpider(scrapy.Spider):
# name表示爬蟲的名字,在`scrapy crawl xx`時(shí)使用
name = “demo”
# allowed_domains定義了爬取的范圍,限定在某幾個(gè)域名內(nèi)
allowed_domains = ['http://www.n#’]
# start_urls定義了從哪里開始爬取
start_urls = ['http://www.n#’]
# parse方法用于接收Downloader返回的結(jié)果
def parse(self,response):
with open('homepage','wb') as f:
f.write(response.body)
這里我們接收到爬取的內(nèi)容后,先寫入到文件homepage中,模擬爬的過程,查看是否正確。
5.3 運(yùn)行爬蟲,使用終端調(diào)試
# 進(jìn)入第二層的Demo目錄內(nèi)
$cd ~/Desktop/Demo/Demo
# 這里的demo即是我們在DemoSpider.py文件中設(shè)置的name屬性
$scrapy crawl demo
會在Demo文件夾下生成一個(gè)homepage文件,使用文本打開,會發(fā)現(xiàn)這就是該網(wǎng)站的html代碼。
6.scrapy的xpath語法
抓取到html后,我們需要對html內(nèi)容進(jìn)行分析,傳統(tǒng)方式是使用正則表達(dá)式。scrapy提供了幾個(gè)方法,可以簡化我們的操作,使查詢更容易。
下面是一些基本語法:
| 語法 | 含義 |
|---|---|
/html/head/title |
選擇HTML文檔中<head>標(biāo)簽內(nèi)的<title>元素 |
/html/head/title/text() |
選擇上面提到的title元素的文本 |
//td |
選擇所有的<td>元素 |
//div[@class='mine'] |
選擇所有具有class='mine'屬性的div元素 |
6.1 測試xpath語法
# 終端輸入,進(jìn)入scrapy shell模式
$scrapy shell "http://www.n#”
# 反饋
2018-10-16 17:04:58 [scrapy.utils.log] INFO: Scrapy 1.5.1 started (bot: scrapybot)
2018-10-16 17:04:58 [scrapy.utils.log] INFO: Versions: lxml 4.2.5.0, libxml2 2.9.8, cssselect 1.0.3, parsel 1.5.0, w3lib 1.19.0, Twisted 18.9.0, Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55) - [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)], pyOpenSSL 18.0.0 (OpenSSL 1.1.0i 14 Aug 2018), cryptography 2.3.1, Platform Darwin-17.5.0-x86_64-i386-64bit
2018-10-16 17:04:58 [scrapy.crawler] INFO: Overridden settings: {'DUPEFILTER_CLASS': 'scrapy.dupefilters.BaseDupeFilter', 'LOGSTATS_INTERVAL': 0}
2018-10-16 17:04:58 [scrapy.middleware] INFO: Enabled extensions:
[‘scrapy.extensions.corestats.CoreStats’,
‘scrapy.extensions.telnet.TelnetConsole’,
‘scrapy.extensions.memusage.MemoryUsage’]
.
.
.
>>>
進(jìn)入該模式后,scrapy Engine會返回給我們一個(gè)response回應(yīng),可以用它查看網(wǎng)頁信息:
>>> response.headers
{b'Server': [b'nginx'], b'Date': [b'Tue, 16 Oct 2018 09:05:56 GMT'], b'Content-Type': [b'text/html; charset=utf-8'], b'Vary': [b'Accept-Encoding'], b'X-Powered-By': [b'PHP/5.3.29'], b'Set-Cookie': [b'PHPSESSID=nd3665jsfcp0cn7b5poc2qcfg3; path=/'], b'Content-Security-Policy': [b'upgrade-insecure-requests’]}
>>>
查詢所有title:
>>> response.xpath('//title’)
[<Selector xpath='//title' data='<title>\n\n 分類目錄網(wǎng)-網(wǎng)站分類目錄大全,好用的網(wǎng)’>]
>>>
注意,這里返回的是Selector對象,如果想得到字符串,可以使用extract()方法,extract()方法會將Selector對象轉(zhuǎn)化為列表對象:
>>> response.xpath('//title').extract()
['<title>\n\n 分類目錄網(wǎng)-網(wǎng)站分類目錄大全,好用的網(wǎng)站導(dǎo)航\n\n </title>’]
>>>
這里返回的是文本列表。
如果想得到title標(biāo)簽的文本內(nèi)容,可以使用下面的語法:
>>> response.xpath('//title/text()').extract()
['\n\n 分類目錄網(wǎng)-網(wǎng)站分類目錄大全,好用的網(wǎng)站導(dǎo)航\n\n ‘]
>>>
6.2 抓取我們的目標(biāo)
通過瀏覽器自帶的審查元素,我們知道需要的站點(diǎn)資訊的ul元素的class屬性為newslist,并且頁面內(nèi)沒有其他與其重復(fù),因此這可以作為關(guān)鍵點(diǎn)來抓取。

>>> response.xpath("http://ul[@class='newslist']").extract()
['<ul class="newslist">\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-10-09\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1800.html">\n\n 工業(yè)門的門洞要求及生產(chǎn)工藝[轉(zhuǎn)載]\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-10-09\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1799.html">\n\n 健康公益中原行啟動(dòng)儀式在鄭州成功舉辦\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-10-08\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1798.html">\n\n 區(qū)塊鏈?zhǔn)鞘裁??區(qū)塊鏈+電商怎么落地呢??\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-10-07\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1796.html">\n\n 簡述工業(yè)門的操控方式及安全性能[轉(zhuǎn)載]\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-29\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1791.html">\n\n 西安格帆“照明空氣凈化器”面向全國招商\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-27\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1787.html">\n\n 區(qū)塊鏈?zhǔn)鞘裁矗繀^(qū)塊鏈+電商怎么落地呢?\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-27\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1786.html">\n\n 2018有哪些免費(fèi)收錄的分類目錄站點(diǎn)\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-27\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1785.html">\n\n 分類目錄網(wǎng)站外鏈還有效果嗎?\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-27\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1783.html">\n\n 想做點(diǎn)小生意,coco奶茶加盟不好做?\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-25\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1775.html">\n\n 傳統(tǒng)行業(yè)如何向互聯(lián)網(wǎng)轉(zhuǎn)型?\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-25\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1774.html">\n\n CentOS7開放關(guān)閉防火墻與端口\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-24\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1772.html">\n\n 通過 CSP 指令解決https加載不了http資源問題\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-21\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1767.html">\n\n 區(qū)塊鏈+電商平臺設(shè)計(jì)\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-17\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1755.html">\n\n windows重裝系統(tǒng)備份還原用戶憑據(jù)方法\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-14\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1752.html">\n\n CentOS 7雙網(wǎng)卡雙IP內(nèi)外網(wǎng)關(guān)配置\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-05\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1733.html">\n\n linux vps修改時(shí)區(qū)設(shè)置\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-09-03\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1729.html">\n\n postgresql 創(chuàng)建數(shù)據(jù)庫 ERROR: new encoding (UTF8) is incompatible\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t\t<li>\n\n\t\t\t\t\t\t<span>\n\n 2018-08-31\n\n\t\t\t\t\t\t</span>\n\n\t\t\t\t\t\t<a href="/artinfo/1724.html">\n\n 為什么工業(yè)門要設(shè)置平衡系統(tǒng)?[轉(zhuǎn)載]\n\n\t\t\t\t\t\t</a>\n\n\t\t\t\t\t\t</li>\n\n \n\t\t\t\t\t</ul>’]
>>>
可以看到,抓到了我們想要的結(jié)果。
6.3 提取title和link
# 獲取Selector對象列表,找到所有l(wèi)i元素的Selector對象
>>> sites = response.xpath('//ul[@class="newslist"]/li’)
>>> for site in sites:
... title = site.xpath('a/text()').extract()
... print(title)
...
['\n\n 工業(yè)門的門洞要求及生產(chǎn)工藝[轉(zhuǎn)載]\n\n\t\t\t\t\t\t’]
['\n\n 健康公益中原行啟動(dòng)儀式在鄭州成功舉辦\n\n\t\t\t\t\t\t’]
['\n\n 區(qū)塊鏈?zhǔn)鞘裁??區(qū)塊鏈+電商怎么落地呢??\n\n\t\t\t\t\t\t’]
['\n\n 簡述工業(yè)門的操控方式及安全性能[轉(zhuǎn)載]\n\n\t\t\t\t\t\t’]
['\n\n 西安格帆“照明空氣凈化器”面向全國招商\n\n\t\t\t\t\t\t’]
['\n\n 區(qū)塊鏈?zhǔn)鞘裁矗繀^(qū)塊鏈+電商怎么落地呢?\n\n\t\t\t\t\t\t’]
['\n\n 2018有哪些免費(fèi)收錄的分類目錄站點(diǎn)\n\n\t\t\t\t\t\t’]
['\n\n 分類目錄網(wǎng)站外鏈還有效果嗎?\n\n\t\t\t\t\t\t’]
['\n\n 想做點(diǎn)小生意,coco奶茶加盟不好做?\n\n\t\t\t\t\t\t’]
['\n\n 傳統(tǒng)行業(yè)如何向互聯(lián)網(wǎng)轉(zhuǎn)型?\n\n\t\t\t\t\t\t’]
['\n\n CentOS7開放關(guān)閉防火墻與端口\n\n\t\t\t\t\t\t’]
['\n\n 通過 CSP 指令解決https加載不了http資源問題\n\n\t\t\t\t\t\t’]
['\n\n 區(qū)塊鏈+電商平臺設(shè)計(jì)\n\n\t\t\t\t\t\t’]
['\n\n windows重裝系統(tǒng)備份還原用戶憑據(jù)方法\n\n\t\t\t\t\t\t’]
['\n\n CentOS 7雙網(wǎng)卡雙IP內(nèi)外網(wǎng)關(guān)配置\n\n\t\t\t\t\t\t’]
['\n\n linux vps修改時(shí)區(qū)設(shè)置\n\n\t\t\t\t\t\t’]
['\n\n postgresql 創(chuàng)建數(shù)據(jù)庫 ERROR: new encoding (UTF8) is incompatible\n\n\t\t\t\t\t\t’]
['\n\n 為什么工業(yè)門要設(shè)置平衡系統(tǒng)?[轉(zhuǎn)載]\n\n\t\t\t\t\t\t’]
>>>
可以看到,獲取了所有標(biāo)題。
>>> for site in sites:
... link = site.xpath('a/@href').extract()
... print(link)
...
['/artinfo/1800.html’]
['/artinfo/1799.html’]
['/artinfo/1798.html’]
['/artinfo/1796.html’]
['/artinfo/1791.html’]
['/artinfo/1787.html’]
['/artinfo/1786.html’]
['/artinfo/1785.html’]
['/artinfo/1783.html’]
['/artinfo/1775.html’]
['/artinfo/1774.html’]
['/artinfo/1772.html’]
['/artinfo/1767.html’]
['/artinfo/1755.html’]
['/artinfo/1752.html’]
['/artinfo/1733.html’]
['/artinfo/1729.html’]
['/artinfo/1724.html’]
>>>
獲取了所有鏈接。不過,這些鏈接都是相對路徑,到代碼中我們需要拼接域名。
7.代碼實(shí)現(xiàn)
代碼實(shí)現(xiàn)的過程,其實(shí)就是將我們在終端中的命令用代碼實(shí)現(xiàn)一遍。
def parse(self,response):
sites = response.xpath("http://ul[@class='newslist']/li")
for site in sites:
title = site.xpath('a/text()').extract()
link = site.xpath('a/@href').extract()
print(title,link)

8.導(dǎo)入item模塊
import scrapy
from Demo.items import DemoItem
class DemoSpider(scrapy.Spider):
# name表示爬蟲的名字,在`scrapy crawl xx`時(shí)使用
name = "demo"
# allowed_domains定義了爬取的范圍,限定在某幾個(gè)域名內(nèi)
allowed_domains = ['http://www.n#']
# start_urls定義了從哪里開始爬取
start_urls = ['http://www.n#']
# parse方法用于接受Downloader返回的結(jié)果
def parse(self,response):
sites = response.xpath("http://ul[@class='newslist']/li")
items = []
for site in sites:
item = DemoItem()
item['title'] = site.xpath('a/text()').extract()[0]
item['link'] = self.allowed_domains[0] + site.xpath('a/@href').extract()[0]
items.append(item)
return items
8.導(dǎo)出抓取結(jié)果
# 將parse函數(shù)返回的結(jié)果進(jìn)行導(dǎo)出,使用json格式
$scrapy crawl demo -o items.json -t json
如果沒有意外,可以看到Demo文件夾下面多了item.json文件,里面就是我們需要抓取的內(nèi)容。
