本博客地址【http://blog.csdn.net/xiantian7】
爬取豆瓣上的链接
item类
class DoubanItem(Item):
groupName = Field()
groupURL = Field()
totalNumber = Field()
RelativeGroups = Field()
ActiveUesrs = Field()
spider类
# coding=utf-8
from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.item import Item
from douban.items import DoubanItem
import re
class doubanSpider(BaseSpider):
name = "douban1"
allowed_domains = ["douban.com"]
start_urls = [
"http://www.douban.com/group/ProductManager/",
]
#在页面中找小组
def __get_id_from_group_url(self, url):
m = re.search("^http://www.douban.com/group/([^/]+)/$", url)
if(m):
#m.group(1) 的值是ProductManager
return m.group(1)
else:
return 0
def parse(self, response):
self.log("Fetch group home page: %s" % response.url)
hxs = HtmlXPathSelector(response)
item = DoubanItem()
#get group name
#为了得到小组名称,使用hxs.select('//h1/text()')得到h1标题的内容,然后用re("^\s+(.*)\s+$")过滤到标题的空格
item['groupName'] = hxs.select('//h1/text()').re("^\s+(.*)\s+$")[0]
#get group id
#需要测试这个reponse.url在使用的时候是否是返回的下一个 待爬取的url
item['groupURL'] = response.url
# response.url中的内容 : http://www.douban.com/group/WHV/
groupid = self.__get_id_from_group_url(response.url)
#get group members number
members_url = "http://www.douban.com/group/%s/members" % groupid
#a[contains(@href, "%s")]是模糊查询
members_text = hxs.select('//a[contains(@href, "%s")]/text()' % members_url).re("\((\d+)\)")
#member_text[0]值成员数
item['totalNumber'] = members_text[0]
#get relative groups
#为了得到小组的相关小组,使用hxs.select('//div[contains(@class, "group-list-item")]')得到一个小组列表,
#然后在for循环中select小组的URL,并append到item['RelativeGroups']数组中
item['RelativeGroups'] = []
groups = hxs.select('//div[contains(@class, "group-list-item")]')
for group in groups:
url = group.select('div[contains(@class, "title")]/a/@href').extract()[0]
item['RelativeGroups'].append(url)
#item['RelativeGroups'] = ','.join(relative_groups)
return item
大部分注释都写在代码中间了,再补充几个:
正则表达式中:
^\s+(.*)\s+$
表示选取一个前面有空格,后面也有空格的一段文字
Item对象是一个装抓取数据的容器。它提供类似dictionary类的函数功能
item['RelativeGroups'].append(url)
所以上面这一条的功能就不用解释了
Scrapy 里面有不同的Spider基类供我们继承,BaseSpider是里面最基本的一个
里面大概有这些方法:
name:蜘蛛名字
allowed_domains:抓取域名范围
start_urls:抓取开始的url
start_requests():但start_urls中没有值的时候,这个方法就会被调用,如果start_urls里面有值make_requests_from_url就会被调用,见第一章中可知,Scrapy的抓取流程是从url中生成抓取的request,然后返回response,再解析response
make_requests_from_url(url):就是生成一个request
parse(response):解析返回值response的函数
log(message[, level, component ]):写入日志log
CrawlSpider是我们常用的基类:
除了上面提到的这些方法,这个基类还有两个自己独有的方法
rules:描述怎么处理遇到的各种url
parse_start_url:用来处理初始化中的url,用来返回一个response或者Item对象
class scrapy.contrib.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)
link_extractor:怎么来解析我们蜘蛛遇到的每一个link
callback:可以是回调函数或者字符串,类里和右这个字符串一样名字的函数将会被调用
cb_kwargs:是一个字典,里面包含了关键词参数,将会传给回调函数
follow:是一个布尔值,指明是否应该使用这个rule,当callback为空的时候,follow 默认为True,不然则为false
process_links:是一个回调函数或者字符串,类里和右这个字符串一样名字的函数将会被调用,被link_extractor抓取出来的每个link都会被这个函数处理,主要是一个过滤的作用
process_request是一个回调函数或者字符串,类里和右这个字符串一样名字的函数将会被调用,每次产生一个request就会调用它,它需要返回none或者一个request
link_extractor其中的一个
class scrapy.contrib.linkextractors.sgml.SgmlLinkExtractor
其中部分参数:
allow:符合这个的链接就抓取
deny:符合这个的链接就不抓取
allow_domains
deny_domains
tags:需要抓取的标签,默认是a 和 area
class GroupSpider(CrawlSpider):
name = "Group"
allowed_domains = ["douban.com"]
start_urls = [
"http://www.douban.com/group/explore?tag=%E8%B4%AD%E7%89%A9",
"http://www.douban.com/group/explore?tag=%E7%94%9F%E6%B4%BB",
"http://www.douban.com/group/explore?tag=%E7%A4%BE%E4%BC%9A",
"http://www.douban.com/group/explore?tag=%E8%89%BA%E6%9C%AF",
"http://www.douban.com/group/explore?tag=%E5%AD%A6%E6%9C%AF",
"http://www.douban.com/group/explore?tag=%E6%83%85%E6%84%9F",
"http://www.douban.com/group/explore?tag=%E9%97%B2%E8%81%8A",
"http://www.douban.com/group/explore?tag=%E5%85%B4%E8%B6%A3"
]
rules = [
Rule(SgmlLinkExtractor(allow=('/group/[^/]+/$', )), callback='parse_group_home_page', process_request='add_cookie'),
Rule(SgmlLinkExtractor(allow=('/group/explore\?tag', )), follow=True, process_request='add_cookie'),
]