制作Spider爬取网页
在Scrapy-Redis中,分别提供了两个爬虫类实现爬取网页的操作:RedisSpider、RedisCrawlSpider,它们都位于scrapy_redis.spiders模块中。其中,RedisSpider是Spider的派生类,RedisCrawlSpider是CrawlSpider类的派生类,它们默认已经拥有了父类中的成员。此外,它们还定义了自己的若干属性,主要包含如下属性:
1. redis_key
表示Redis数据库从哪里获取起始网址,它是一个队列的名称,相当于start_urls。项目启动时,不会立即执行爬取操作,而是停在原地等待命令。例如,现在有5台机器,每台机器都已经把项目启动起来,它们都等待着redis_key指令,将第一批请求给它们执行,这样就做到了任务统一调度。
redis_key的一般命名格式为:
类名(小写): start_urls
redis_key的示例如下:
redis_key = 'aqi:start_urls'
有时,我们需要将爬取到的URL存放在远程的Redis数据库中,所以一般有如下操作:
redis = Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB,
password=REDIS_PASSWD)
# spider:start_urls是Redis中存放url的队列名称
redis.lpush('spider:start_urls', self.url + u)
连接到数据库存放URL,这样可以保证不断有URL添加,爬虫能够一直继续下去。
2. allowed_domains
这个属性既可以按照Spider中原有的写法,直接给出爬虫搜索的域名范围,也可以动态获取域名。例如,redis_key的值为“hr.tencent.com”,allowed_domains属性能自动获取到这个域名,将其作为允许的域名范围,具体设置如下:
def __init__(self, *args, **kwargs):
domain = kwargs.pop('domain', '')
self.allowed_domains = filter(None, domain.split(','))
super(**当前类名**, self).__init__(*args, **kwargs)
两种设置使用哪种都可以,可任选其一。
在mySpider项目中,创建一个用于编写爬虫的文件,命名为itcast,爬取域的范围为“itcast.cn”。在终端中切换目录至spiders,输入如下命令:
scrapy genspider itcast "itcast.cn"
运行上述命令,PyCharm的spiders目录下增加了itcast.py文件。在该文件中,默认生成的类代码中已经继承了scrapy.Spider类。为了能让其具有Scrapy-Redis的功能,需要把继承的父类修改为RedisSpider,另外还要删除该文件中自带的start_urls,增加redis_key属性的设置,具体代码如下。
# -*- coding: utf-8 -*-
import scrapy
from scrapy_redis.spiders import RedisSpider
class ItcastSpider(RedisSpider):
name = 'itcast'
allowed_domains = ['itcast.cn']
redis_key = 'itcast:start_urls'
def parse(self, response):
pass
接下来就可以解析网页了。在parse方法中,将得到的数据封装成一个MyspiderItem对象,每个对象保存一个讲师的信息,然后将所有的对象保存在一个列表items里。代码如下所示。
def parse(self, response):
items = [] #存放老师信息的集合
for each in response.xpath("//div[@class='li_txt']"):
# 将我们得到的数据封装到一个'MyspiderItem'对象
item = MyspiderItem()
# extract方法返回的都是Unicode字符串
name = each.xpath("h3/text()").extract()
title = each.xpath("h4/text()").extract()
info = each.xpath("p/text()").extract()
# XPath返回的是包含一个元素的列表
item["name"] = name[0]
item["title"] = title[0]
item["info"] = info[0]
items.append(item)
# 返回数据,不经过pipeline
return items
我们之前在项目的mySpider/items.py目录下定义了MyspiderItem类,需要将该类引入到itcast.py文件中,代码如下。
from mySpider.items import MyspiderItem