记得n年前项目须要一个灵活的爬虫工具,就组织了一个小团队用Java实现了一个爬虫框架,能够根据目标网站的结构、地址和须要的内容,作简单的配置开发,便可实现特定网站的爬虫功能。由于要考虑到各类特殊情形,开发还耗了很多人力。后来发现了Python下有这个Scrapy工具,瞬间以为以前作的事情都白费了。对于一个普通的网络爬虫功能,Scrapy彻底胜任,并把不少复杂的编程都包装好了。本文会介绍如何Scrapy构建一个简单的网络爬虫。python
一个基本的爬虫工具,它应该具有如下几个功能:git
咱们来看下Scrapy怎么作到这些功能的。首先准备Scrapy环境,你须要安装Python(本文使用v2.7)和pip,而后用pip来安装lxml和scrapy。我的强烈建议使用virtualenv来安装环境,这样不一样的项目之间不会冲突。详细步骤这里就不赘述了。对于Mac用户要注意,当使用pip安装lxml时,会出现相似于的下面错误:github
Error: #include “xml/xmlversion.h” not foundchrome
解决这个问题,你须要先安装Xcode的command line tools,具体的方法是在命令行执行下面的命令便可。数据库
1
|
$ xcode-select --install
|
环境安装好以后,咱们来用Scrapy实现一个简单的爬虫,抓取本博客网站的文章标题,地址和摘要。编程
1
|
$ scrapy startproject my_crawler
|
该命令会在当前目录下建立一个名为”my_crawler”的工程,工程的目录结构以下json
1
2
3
4
5
6
7
8
|
my_crawler
|- my_crawler
| |- spiders
| | |- __init__.py
| |- items.py
| |- pipelines.py
| |- setting.py
|- scrapy.cfg
|
修改”items.py”文件,在”MyCrawlerItem”类中加上以下代码:xcode
1
2
3
4
5
6
7
8
|
# -*- coding: utf-8 -*-
import scrapy
class MyCrawlerItem(scrapy.Item):
title = scrapy.Field() # 文章标题
url = scrapy.Field() # 文章地址
summary = scrapy.Field() # 文章摘要
pass
|
在”my_crawler/spiders”目录下,建立一个名为”crawl_spider.py”文件(文件名能够任意取)。代码以下网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from my_crawler.items import MyCrawlerItem
class MyCrawlSpider(CrawlSpider):
name = 'my_crawler' # Spider名,必须惟一,执行爬虫命令时使用
allowed_domains = ['bjhee.com'] # 限定容许爬的域名,可设置多个
start_urls = [
"http://www.bjhee.com", # 种子URL,可设置多个
]
rules = ( # 对应特定URL,设置解析函数,可设置多个
Rule(LinkExtractor(allow=r'/page/[0-9]+'), # 指定容许继续爬取的URL格式,支持正则
callback='parse_item', # 用于解析网页的回调函数名
follow=True
),
)
def parse_item(self, response):
# 经过XPath获取Dom元素
articles = response.xpath('//*[@id="main"]/ul/li')
for article in articles:
item = MyCrawlerItem()
item['title'] = article.xpath('h3[@class="entry-title"]/a/text()').extract()[0]
item['url'] = article.xpath('h3[@class="entry-title"]/a/@href').extract()[0]
item['summary'] = article.xpath('div[2]/p/text()').extract()[0]
yield item
|
对于XPath不熟悉的朋友,能够经过Chrome的debug工具获取元素的XPath。框架
在命令行中输入:
1
|
$ scrapy crawl my_crawler
|
注意,这里的”my_crawler”就是你在”crawl_spider.py”文件中起的Spider名。
没过几秒钟,你就会看到要抓取的字段内容打印在控制台上了。就是这么神奇!Scrapy将HTTP(S)请求,内容下载,待抓取和已抓取的URL队列的管理都封装好了。你的主要工做基本上就是设置URL规则及编写解析的方法。
咱们将抓取的内容保存为JSON文件:
1
|
$ scrapy crawl my_crawler -o my_crawler.json -t json
|
你能够在当前目录下,找到文件”my_crawler.json”,里面保存的就是咱们要抓取的字段信息。(参数”-t json”能够省去)
这里咱们采用MongoDB,你须要先安装Python的MongoDB库”pymongo”。编辑”my_crawler”目录下的”pipelines.py”文件,在”MyCrawlerPipeline”类中加上以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
# -*- coding: utf-8 -*-
import pymongo
from scrapy.conf import settings
from scrapy.exceptions import DropItem
class MyCrawlerPipeline(object):
def __init__(self):
# 设置MongoDB链接
connection = pymongo.Connection(
settings['MONGO_SERVER'],
settings['MONGO_PORT']
)
db = connection[settings['MONGO_DB']]
self.collection = db[settings['MONGO_COLLECTION']]
# 处理每一个被抓取的MyCrawlerItem项
def process_item(self, item, spider):
valid = True
for data in item:
if not data: # 过滤掉存在空字段的项
valid = False
raise DropItem("Missing {0}!".format(data))
if valid:
# 也能够用self.collection.insert(dict(item)),使用upsert能够防止重复项
self.collection.update({'url': item['url']}, dict(item), upsert=True)
return item
|
再打开”my_crawler”目录下的”settings.py”文件,在文件末尾加上pipeline的设置:
1
2
3
4
5
6
7
8
9
10
11
|
ITEM_PIPELINES = {
'my_crawler.pipelines.MyCrawlerPipeline': 300, # 设置Pipeline,能够多个,值为执行优先级
}
# MongoDB链接信息
MONGO_SERVER = 'localhost'
MONGO_PORT = 27017
MONGO_DB = 'bjhee'
MONGO_COLLECTION = 'articles'
DOWNLOAD_DELAY=2 # 若是网络慢,能够适当加些延迟,单位是秒
|
1
|
$ scrapy crawl my_crawler
|
别忘了启动MongoDB并建立”bjhee”数据库哦。如今你能够在MongoDB里查询到记录了。
总结下,使用Scrapy来构建一个网络爬虫,你须要作的就是:厦门叉车租赁公司
其余的事情,Scrapy都帮你作了。下图就是Scrapy具体工做的流程。怎么样?开始写一个本身的爬虫吧。
本例中的代码能够在这里下载。