01-核心组件
·五大核心组件的工作流程:
引擎(Scrapy)
用来处理整个系统的数据流处理, 触发事务(框架核心)
调度器(Scheduler)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
下载器(Downloader)
用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
爬虫(Spiders)
爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
项目管道(Pipeline)
负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
02-post请求
# postPro/postPro/spiders/postDemo.py # -*- coding: utf-8 -*- import scrapy # 需求:百度翻译中指定词条对应的翻译结果进行获取 class PostdemoSpider(scrapy.Spider): name = 'postDemo' # allowed_domains = ['www.baidu.com'] start_urls = ['https://fanyi.baidu.com/sug'] # start_requests 该方法其实是父类中的一个方法:该方法可以对 start_urls 列表中的元素进行get请求的发送 # 发起post请求的方式:① 将Request 方法中method参数赋值成post(不建议);② FormRequest()可以发起post请求(推荐) # 要想发起post请求,一定要对父类中的 start_requests 进行重写。 def start_requests(self): print("执行了start_requests") # post的请求参数 data = { 'kw': 'dog', } for url in self.start_urls: # formdata: 请求参数对应的字典 yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse) def parse(self, response): print(response.text)
03-cookie操作
# doubanPro/doubanPro/spiders/douban.py # -*- coding: utf-8 -*- import scrapy class DoubanSpider(scrapy.Spider): name = 'douban' # allowed_domains = ['www.baidu.com'] start_urls = ['https://accounts.douban.com/login'] def start_requests(self): data = { "source": "index_nav", "redir": "https: // www.douban.com/", "form_email": "18844170520@163.com", "form_password": "******", "login": "登录", } for url in self.start_urls: yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse) def parseBySecondPage(self, response): # 针对个人主页面数据进行解析操作 fp = open('./second.html', 'w', encoding='utf-8') fp.write(response.text) def parse(self, response): # 登陆成功后的页面进行存储 fp = open('./main.html', 'w', encoding='utf-8') fp.write(response.text) # 获取当前用户的个人主页 url = 'https://www.douban.com/people/187468735/' yield scrapy.Request(url=url, callback=self.parseBySecondPage)
04-代理
下载中间件的作用: 拦截请求, 可以将IP的请求进行更换。 流程: 1.下载中间件类的自制定 class MyProxy(object): def process_request(self, request, spider): # 请求IP的更换 request.meta['proxy'] = "http://120.76.77.152:9999" 2.配置文件中进行下载中间件的开启。
# proxyPro/settings.py # 打开配置文件中的下载中间件,并配置自定义中间件 # 下载中间件 DOWNLOADER_MIDDLEWARES = { # 'proxyPro.middlewares.ProxyproDownloaderMiddleware': 543, 'proxyPro.middlewares.MyProxy': 543, }
# proxyPro/middlewares.py from scrapy import signals # 自定义一个下载中间件的类,在类中事先process_request(处理中间件拦截到的请求) 方法 class MyProxy(object): def process_request(self, request, spider): # 请求IP的更换 request.meta['proxy'] = "http://120.76.77.152:9999"
# proxyPro/proxyDemo.py # -*- coding: utf-8 -*- import scrapy class ProxydemoSpider(scrapy.Spider): name = 'proxyDemo' # allowed_domains = ['www.baidu.com/s?wd=ip'] start_urls = ['http://www.baidu.com/s?wd=ip'] def parse(self, response): fp = open('./proxy.html', 'w', encoding='utf-8') fp.write(response.text)
05-日志等级
# settings.py # 指定终端输出日志等级 LOG_LEVEL = 'ERROR' # 把终端输出的日志信息写入到log.txt文件中 LOG_FILE = 'log.txt'
06-请求传参(meta)
解决问题:爬取的数据值不在同一个页面。
需求:将id97电影网站中的电影详情数据进行爬取
# moviePro/spiders/movie.py # -*- coding: utf-8 -*- import scrapy from moviePro.items import MovieproItem class MovieSpider(scrapy.Spider): name = 'movie' # allowed_domains = ['www.id97.com'] start_urls = ['http://www.id97.com/movie'] # 专门对二级页面进行解析 def parseBySecondPage(self, response): # 导演 actor = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[1]/td[2]/a/text()').extract_first() # 语言 language = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[6]/td[2]/text()').extract_first() # 片长 longTime = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[8]/td[2]/text()').extract_first() # 取出Request 方法的meta 参数传递过来的字典(request.meta) item = response.meta['item'] item['actor'] = actor item['language'] = language item['longTime'] = longTime # 将item提交给管道 yield item def parse(self, response): # 名称,类型,导演,语言,片长 div_list = response.xpath('/html/body/div[1]/div[1]/div[2]/div') for div in div_list: # 片名 name = div.xpath('.//div[@class="meta"]/h1/a/text()').extract_first() # 类型 如下方法返回的是一个列表,且列表元素为4 kind = div.xpath('.//div[@class="otherinfo"]//text()').extract() # 转化为字符串 kind = "".join(kind) # 详情页的url url = div.xpath('.//div[@class="meta"]/h1/a/@href').extract_first() # 创建item对象 item = MovieproItem() item['name'] = name item['kind'] = kind # 问题:如何将剩下的电影详情数据存储到item对象(meta参数) # 需要对url发起请求,获取页面数据,进行指定的数据解析, meta会将字典传递给回调函数 # meta 只可以赋值为 一个字典 yield scrapy.Request(url=url, callback=self.parseBySecondPage, meta={'item': item})
07-CrawlSpider
# 创建项目文件 scrapy startproject crawlSpiderPro scrapy genspider -t crawl chouti https://dig.chouti.com
# spiders/chouti.py # -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule ''' LinkExtractor : 链接提取器对应的类 LinkExtractor(allow=r'Items/') 实例化 作用:用来提取指定的url,allow参数:赋值一个正则表达式,就可以根据正则在页面中提取指定的url 提取到的链接url 会全部交给 规则解析器Rule, Rule : 规则解析器对应的类 Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True), Rule 接受了 LinkExtractor 发送的链接url后,就会对链接发起请求,获取url对应的页面内容, 然后就会根据 指定的规则 对页面内容进行指定的页面解析, callback:指定了一个解析规则 parse_item(方法/函数) follow:是否将 链接提取器 继续作用到 链接提取器提取出的链接 所表示的页面数据中 ''' class ChoutiSpider(CrawlSpider): name = 'chouti' # allowed_domains = ['https://dig.chouti.com'] start_urls = ['https://dig.chouti.com/'] rules = ( # 实例化了一个规则解析器对象 Rule(LinkExtractor(allow=r'/all/hot/recent/d+'), callback='parse_item', follow=True), ) def parse_item(self, response): print(response) # 再进行数据解析......... # i = {} # # i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract() # # i['name'] = response.xpath('//div[@id="name"]').extract() # # i['description'] = response.xpath('//div[@id="description"]').extract() # return i