1.前提
1.1 使用Mac OS系统
1.2 Python3.x版本
1.3 因为mac系统自带python2.7,因此必须在终端将版本修改为python3.x版本
终端执行:
$sudo vim ~/.bash_profile
在bash_profile文件中增加下面的语句,需要安装python3时的路径:
alias python='/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6’
终端执行,使之生效:
$source ~/.bash_profile
2.安装Scrapy
Python3.6.5安装包中默认带有pip3命令,直接使用即可。
$pip3 install scrapy
注意:如果使用了
pip install scrapy,则安装的scrapy将会默认搜索python2.7相关文件。这会在我们运行测试的时候报错,因为我们所有的语法和scrapy都是基于python3.x的!
终端应该输入以下内容:
$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
默认同时安装了几个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,默认会查找python2.7版本的包,使我们的测试失败。因为我们这里使用python3,因此这点需要特别注意。
4.创建Scrapy项目
在桌面创建了一个Demo工程
$cd Desktop
$scrapy startproject Demo
scrapy startproject:创建一个scrapy项目。
以下是项目的目录结构:
Demo/
scrapy.cfg
Demo/
__init__.py
items.py
pipelines.py
settings.py
middlewares.py
spiders/
__init__.py
......
5.编写代码
使用Scrapy抓取一个网站需要四个步骤:
- 创建一个Scrapy项目
- 定义Item容器
- 编写爬虫
- 存储内容
5.1 设置抓取网站并建模
这里我们采用http://www.n360.cn网站的站点资讯资源:

我们需要抓取的是该板块的
标题和链接。
在项目中,我们在items.py文件中建立相应的字段:
import scrapy
class DemoItem(scrapy.Item):
#define the fields for you item here like:
#name = scrapy.Field()
title = scrapy.Field() #抓取的标题
link = scrapy.Field() #抓取的链接
5.2 编写爬虫
在项目的Spider目录中,创建名为DemoSprider.py的文件,编写爬虫代码:
import scrapy
class DemoSpider(scrapy.Spider):
# name表示爬虫的名字,在`scrapy crawl xx`时使用
name = “demo”
# allowed_domains定义了爬取的范围,限定在某几个域名内
allowed_domains = ['http://www.n360.cn’]
# start_urls定义了从哪里开始爬取
start_urls = ['http://www.n360.cn’]
# parse方法用于接收Downloader返回的结果
def parse(self,response):
with open('homepage','wb') as f:
f.write(response.body)
这里我们接收到爬取的内容后,先写入到文件homepage中,模拟爬的过程,查看是否正确。
5.3 运行爬虫,使用终端调试
# 进入第二层的Demo目录内
$cd ~/Desktop/Demo/Demo
# 这里的demo即是我们在DemoSpider.py文件中设置的name属性
$scrapy crawl demo
会在Demo文件夹下生成一个homepage文件,使用文本打开,会发现这就是该网站的html代码。
6.scrapy的xpath语法
抓取到html后,我们需要对html内容进行分析,传统方式是使用正则表达式。scrapy提供了几个方法,可以简化我们的操作,使查询更容易。
下面是一些基本语法:
| 语法 | 含义 |
|---|---|
/html/head/title |
选择HTML文档中<head>标签内的<title>元素 |
/html/head/title/text() |
选择上面提到的title元素的文本 |
//td |
选择所有的<td>元素 |
//div[@class='mine'] |
选择所有具有class='mine'属性的div元素 |
6.1 测试xpath语法
# 终端输入,进入scrapy shell模式
$scrapy shell "http://www.n360.cn”
# 反馈
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’]
.
.
.
>>>
进入该模式后,scrapy Engine会返回给我们一个response回应,可以用它查看网页信息:
>>> 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 分类目录网-网站分类目录大全,好用的网’>]
>>>
注意,这里返回的是Selector对象,如果想得到字符串,可以使用extract()方法,extract()方法会将Selector对象转化为列表对象:
>>> response.xpath('//title').extract()
['<title>\n\n 分类目录网-网站分类目录大全,好用的网站导航\n\n </title>’]
>>>
这里返回的是文本列表。
如果想得到title标签的文本内容,可以使用下面的语法:
>>> response.xpath('//title/text()').extract()
['\n\n 分类目录网-网站分类目录大全,好用的网站导航\n\n ‘]
>>>
6.2 抓取我们的目标
通过浏览器自带的审查元素,我们知道需要的站点资讯的ul元素的class属性为newslist,并且页面内没有其他与其重复,因此这可以作为关键点来抓取。

>>> response.xpath("//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 工业门的门洞要求及生产工艺[转载]\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 健康公益中原行启动仪式在郑州成功举办\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 区块链是什么?区块链+电商怎么落地呢??\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 简述工业门的操控方式及安全性能[转载]\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 区块链是什么?区块链+电商怎么落地呢?\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有哪些免费收录的分类目录站点\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 分类目录网站外链还有效果吗?\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 想做点小生意,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 传统行业如何向互联网转型?\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开放关闭防火墙与端口\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 区块链+电商平台设计\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重装系统备份还原用户凭据方法\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双网卡双IP内外网关配置\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修改时区设置\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 创建数据库 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 为什么工业门要设置平衡系统?[转载]\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>’]
>>>
可以看到,抓到了我们想要的结果。
6.3 提取title和link
# 获取Selector对象列表,找到所有li元素的Selector对象
>>> sites = response.xpath('//ul[@class="newslist"]/li’)
>>> for site in sites:
... title = site.xpath('a/text()').extract()
... print(title)
...
['\n\n 工业门的门洞要求及生产工艺[转载]\n\n\t\t\t\t\t\t’]
['\n\n 健康公益中原行启动仪式在郑州成功举办\n\n\t\t\t\t\t\t’]
['\n\n 区块链是什么?区块链+电商怎么落地呢??\n\n\t\t\t\t\t\t’]
['\n\n 简述工业门的操控方式及安全性能[转载]\n\n\t\t\t\t\t\t’]
['\n\n 西安格帆“照明空气净化器”面向全国招商\n\n\t\t\t\t\t\t’]
['\n\n 区块链是什么?区块链+电商怎么落地呢?\n\n\t\t\t\t\t\t’]
['\n\n 2018有哪些免费收录的分类目录站点\n\n\t\t\t\t\t\t’]
['\n\n 分类目录网站外链还有效果吗?\n\n\t\t\t\t\t\t’]
['\n\n 想做点小生意,coco奶茶加盟不好做?\n\n\t\t\t\t\t\t’]
['\n\n 传统行业如何向互联网转型?\n\n\t\t\t\t\t\t’]
['\n\n CentOS7开放关闭防火墙与端口\n\n\t\t\t\t\t\t’]
['\n\n 通过 CSP 指令解决https加载不了http资源问题\n\n\t\t\t\t\t\t’]
['\n\n 区块链+电商平台设计\n\n\t\t\t\t\t\t’]
['\n\n windows重装系统备份还原用户凭据方法\n\n\t\t\t\t\t\t’]
['\n\n CentOS 7双网卡双IP内外网关配置\n\n\t\t\t\t\t\t’]
['\n\n linux vps修改时区设置\n\n\t\t\t\t\t\t’]
['\n\n postgresql 创建数据库 ERROR: new encoding (UTF8) is incompatible\n\n\t\t\t\t\t\t’]
['\n\n 为什么工业门要设置平衡系统?[转载]\n\n\t\t\t\t\t\t’]
>>>
可以看到,获取了所有标题。
>>> 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.代码实现
代码实现的过程,其实就是将我们在终端中的命令用代码实现一遍。
def parse(self,response):
sites = response.xpath("//ul[@class='newslist']/li")
for site in sites:
title = site.xpath('a/text()').extract()
link = site.xpath('a/@href').extract()
print(title,link)

8.导入item模块
import scrapy
from Demo.items import DemoItem
class DemoSpider(scrapy.Spider):
# name表示爬虫的名字,在`scrapy crawl xx`时使用
name = "demo"
# allowed_domains定义了爬取的范围,限定在某几个域名内
allowed_domains = ['http://www.n360.cn']
# start_urls定义了从哪里开始爬取
start_urls = ['http://www.n360.cn']
# parse方法用于接受Downloader返回的结果
def parse(self,response):
sites = response.xpath("//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.导出抓取结果
# 将parse函数返回的结果进行导出,使用json格式
$scrapy crawl demo -o items.json -t json
如果没有意外,可以看到Demo文件夹下面多了item.json文件,里面就是我们需要抓取的内容。
