scrapy的CrawlSpider类
在默认的情况下,scrapy都是继承spider类来进行爬取,但是scrapy还有另一个更好用,更适合大网站的类:CrawlSpider。可以说到了爬虫后期学习对网站级的爬取就是必须要用crawlspider类了。
这个实例就是吧所有的中国慕课里的网站爬下来。
url='https://www.icourse163.org/'
步骤零
由于使用到了CrawlSpider所以在爬虫里导入如下几个包
from scrapy.spiders import CrawlSpider, Rule, Request
from scrapy.linkextractors import LinkExtractor
from scrapy import FormRequest
上述包中,CrawlSpider就是我们所要学习的对象,Rule是可以配合Crawl来使用以遍历全站的包,linkExtractor是配合Rule进行URL规则匹配的包,FromRequest就是用来做登陆的一个包。
在setting中,我们要关闭对robots协议的遵顼,启用cookie的自动传递,开启DONLOADER_MIDDLEWARES中的cookiemiddleware而不知道依赖关系的直接参数设为700参考如下网页http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/settings.html#std:setting-DOWNLOADER_MIDDLEWARES_BASE
ROBOTSTXT_OBEY = False
COOKIES_ENABLED = True
DOWNLOADER_MIDDLEWARES = {
# 'mooc1.middlewares.Mooc1DownloaderMiddleware': 543,
'scrapy.downloadermiddleware.cookies.CookiesMiddleware':700,
}
步骤一:
在完成了准备工作之后,我们可以应用一下CrawlSpider的强大功能了。
这里其中需要注意的是rules里的内容:
class scrapy.contrib.spiders.Rule (
link_extractor, callback=None,cb_kwargs=None,follow=None,process_links=None,process_request=None )
其中:
1. link_extractor为LinkExtractor,用于定义需要提取的链接。
2. callback参数:当link_extractor获取到链接时参数所指定的值作为回调函数。callback参数使用注意:
当编写爬虫规则时,请避免使用parse作为回调函数。于CrawlSpider使用parse方法来实现其逻辑,如果您覆盖了parse方法,crawlspider将会运行失败。
3. follow:指定了根据该规则从response提取的链接是否需要跟进。当callback为None,默认值为true。
4. process_links:主要用来过滤由link_extractor获取到的链接。
5. process_request:主要用来过滤在rule中提取到的request。
对于LinkExtractor:
classscrapy.contrib.linkextractors.sgml.SgmlLinkExtractor(
allow=(),deny=(),allow_domains=(),deny_domains=(),deny_extensions=None,restrict_xpaths=(),tags=('a','area'),attrs=('href'),canonicalize=True,unique=True,process_value=None)
- allow:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。
- deny:与这个正则表达式(或正则表达式列表)不匹配的URL一定不提取。
- allow_domains:会被提取的链接的domains。
- deny_domains:一定不会被提取链接的domains。
- restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。
对于allow中特别要注意他的正则表达式,如果只是写’.com/’会把所有com后面还带东西的都链接到,一定要加上’$’表示结尾,非常的严谨。
而在处理函数中使用try,except就算pass了任然会扩展到其链接到的页面里。
# -*- coding: utf-8 -*-
import scrapy
import re
from scrapy.spiders import CrawlSpider, Rule, Request
from scrapy.linkextractors import LinkExtractor
from scrapy import FormRequest
class MoocSpider(CrawlSpider):
name = 'mooc'
#allowed_domains = ['www.icourse163.org']
start_urls = ['http://www.icourse163.org/']
rules = (
Rule(LinkExtractor(allow=(r'^https://www.icourse163.org.*')), callback='parsess', follow = True),
)
def parsess(self, response):
try:
urll = re.findall(r'university/.*', response.url)[0][11:]
with open('url.txt', 'a') as f:
f.write(urll + '\n')
except:
pass
step2:
在初步使用了CrawlSpider后,会发现其课程对于非注册用户都是非显示的必须要登陆且参与课程后才有资格看一门课里面具体的内容(而实际上,课程的许多内容都是动态显示的,登陆上去还不够,还需要用到scrapy-splash)。
所以我们要先登陆上网站,那么先需要分析一下网站的接口和表单内容。
但是其实mooc的登陆就不好找,在经历了多次尝试后,发现其单独的登陆界面如下:
url = 'https://www.icourse163.org/member/login.htm#/login'
搞了两天网易的接口进不去,只好使用cookie来进入了。那么打开开发者工具,取出Cookies,将Cookie转码,而后用scrapy去模拟登陆
class transCookie:
def __init__(self, cookie):
self.cookie = cookie
def stringToDict(self):
itemDict = {}
items = self.cookie.split(';')
for item in items:
key = item.split('=')[0].replace(' ', '')
value = item.split('=')[1]
itemDict[key] = value
return itemDict
if __name__ == "__main__":
cookie = ''#你的cookie
trans = transCookie(cookie)
print(trans.stringToDict())
step3:
尝试学习使用cookie,则其实重写start_requests加个属性即可,使用CrawlSpider也是一样重写一下start_requests。
下面两份代码上面是测试cookie,下面是使用cookie。
需要具体看整个网页的js推荐使用splash,scrapy-splash的配置这里不再赘述,详见scrapy-splash的学习。
# -*- coding: utf-8 -*-
import scrapy
import re
from scrapy.spiders import CrawlSpider, Rule, Request
from scrapy.linkextractors import LinkExtractor
from scrapy import FormRequest
from scrapy_splash import SplashRequest
class MoocSpider(scrapy.Spider):
name = 'mooc'
#allowed_domains = ['www.icourse163.org']
#start_urls = ['http://www.icourse163.org/']
cookie = {}
headers = {
'Connection': 'keep - alive', # 保持链接状态
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
'Referer': 'https://www.icourse163.org/'
}
def start_requests(self):
yield SplashRequest(url = 'https://www.icourse163.org/user/setting/personInfoEdit.htm#/setting', headers=self.headers, cookies=self.cookie, callback=self.parse)
def parse(self, response):
print(response.url)
with open('user.txt', 'wb') as f:
f.write(response.body)
下面这个代码需要注意进入parsess时,不能再用scrapy.Request了,因为Crawlspider是去重的,会导致没有结果,这里折腾了很久,需要注意。
# -*- coding: utf-8 -*-
import scrapy
import re
from scrapy.spiders import CrawlSpider, Rule, Request
from scrapy.linkextractors import LinkExtractor
from scrapy import FormRequest
from scrapy_splash import SplashRequest
class MoocSpider(CrawlSpider):
name = 'mooc'
#allowed_domains = ['www.icourse163.org']
#start_urls = ['http://www.icourse163.org/']
cookie = {}
headers = {
'Connection': 'keep - alive', # 保持链接状态
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
'Referer': 'https://www.icourse163.org/'
}
rules = (
Rule(LinkExtractor(allow=(r'^https://www.icourse163.org.*')), callback='parses', follow = True),
)
def start_requests(self):
yield scrapy.Request(url = 'http://www.icourse163.org/', headers=self.headers, cookies=self.cookie)
def parses(self, response):
file = response.url.split('/')[-1].split('.')[0]
file = file + '.txt'
with open('./web/' + file, 'wb') as f:
f.write(response.body)
if file == "personInfoEdit.txt":
with open('ser2.txt', 'wb') as f:
f.write(response.body)
yield SplashRequest(url=response.url, headers=self.headers, cookies=self.cookie, callback=self.parsess)
def parsess(self, response):
with open('user2.txt', 'wb') as f:
f.write(response.body)