requests
一、get请求:
网页数据是url直接加载出来的,一般是没有数据跟随的
requests.get(url= url, params= params, hearders= hearders)
其中url就是请求url的地址,如果url地址后缀是跟随用户参数的,就使用params进行用户参数的拾取,headers就是UA防伪
二、pos请求:
网页数据是阿贾克斯请求,即数据的更新不会改变url,一般会跟随数据,进行响应页面显示
requests.post(url= url, data= data, headers= headers)
其他都一样,data就是需要跟随的数据
数据解析
一、正则
此处略过
二、bs4
from bs4 import BeautifulSoup
-对象的实例化:
-1.将本地的html文档中的数据加载到该对象中
fb = open("./test.html", "r", encoding="utf-8")
soup = BeautifulSoup(fp, "lxml")
-2.将互联网上获取的页面源码加载到该对象中
page_text = response.text
soup = BeautifulSoup(page_text, "lxml")
-提供的用于数据解析的方法和属性:
-soup.tagName: 返回的是文档中第一次出现的tagName对应的标签
-soup.find():
-find("tagName") : 等同于soup.tagName
-属性定位:
-soup.find("div", class_/id/attr="song")
-soup.find_all("tagName"): 返回一个符合要求的所有标签的列表
-select:
-select("某种选择器(id, class, 标签 . . . 选择器)"),返回一个列表
-层级选择器:
- soup.select(" . tang > ul > li > a "): > 表示的是一个层级
- soup.seleect(" . tang > ul a "):空格表示的是多个层级
-获取标签之间的文本数据:
- soup.a.text / string / get_text ( )
-text / get_text(): 可以获取某一个标签总所有的文本内容,即使不属于直系
-string():只可以获取该标签直系的文本内容
-获取标签中属性值:
-soup.a["href"]
三、xpth解析
最常用且最便捷高效的一种解析方式,通用
- xpath解析原理:
-1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中
-2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获
- 环境的安装:
- pip install lxml
- 如何实例化一个etree对象: from lxml import etree
-1.将本地的html文文档中的源码数据加载到etree对象中:
etree.parse(filePath)
-2.可以将从互联网上获取的源码数据加载到该对象中:
etree.HTML("page_text")
- xpath表达式
- / : 表示的是从根节点开始定位。表示的是一个层级
- //: 表示的是多个层级。可以表示从任何位置定位
- 属性定位://div[@class="song"]
- 多属性定位://div[@class='song' and @name='d']
- 索引定位://div[@class="song"]/p[3] 索引是从1开始计算的
- 文本定位://*[text()='新闻']
- 常用函数
- contains://*[contains(@class,"新")]
//*[contains(text(), "新")]
- 取文本:
- /text(): 获取的是标签中直系的文本内容
- //text(): 获去的是标签中非直系的文本内容(所有的文本内容)
- 取属性:
- /@attrName
- 伪元素:有些特定数据是在调用页面的时候才会进行接口通信生成,常见于下拉
列表
- :: defore ::
- :: after ::
- 定位伪元素: 通过cssselector(直接复制页面中的文本)
验证码识别
- 人工肉眼识别 (不推荐)
- 第三方自动识别(推荐)
- 云打码:http://www.yundama.com/demo.html
- 云打码的使用流程:
- 注册:普通和开发者用户
- 登录:
- 普通用户的登录:查询该用户是否还有剩余的积分
- 开发者用户的登录:
- 创建一个软件: 我的软件》添加新软件》录入软件名称》提交(软件id和秘钥)
- 下载示例代码:开发文档》点此下载: 云打码接口DLL》pythonHTTP示例下载
- 超级鹰使用流程同上
实战:识别古诗文网登录页面中的验证码。
使用打码平台识别验证码的编码流程:
- 将验证码图片进行本地下载
- 调用平台提提供的实例代码进行图片数据识别
模拟登陆
- 爬取基于某些用户的用户信息
需求:对人人网进行模拟登陆
- 点击登陆按钮后会发起一个post请求
- post请求中会携带登陆之前录入的登陆信息(用户名,密码,验证码。。。)
- 验证码:每次请求都会变化
需求:登陆完后,爬取当前用户的相关用户信息(个人主页中显示的用户信息)
-http/https协议特性:无状态
- 没有请求到对应页面数据的原因:
- 发起的第二次基于个人主页页面请求的时候,服务器端并不知道此请求是基于登
陆状态下的请求
- cookoe:用来让服务器端记录客户端的相关状态
- 手动处理:通过抓包工具获取cookie值,将该值封装到headers中
- 自动处理:
- cookie值的来源是哪里?
- 模拟登陆post请求后,由服务器端创建
session会话对象:
- 作用:
1.可以进行请求的发送
2.如果请求过程中产生了cookie,则该cookie会被自动存储/携
带在该session对象中
- 创建一个session对象:session = request.Session()
- 使用session对象进行模拟登陆post请求的发送(cookie会被存储在
session中)
- session对象对个人主页对应的get请求进行发送(携带了cookie)
代理
破解封IP这种反扒机制
什么是代理:
- 代理服务器
代理的作用:
- 突破自身IP访问的限制
- 隐藏自身真是IP
代理的相关网站
- 快代理
- 西祠代理
- www.goubanjia.com
代理IP的类型
- http:应用到http协议对应的url中
-https:应用到https协议对的url中代理IP的匿名度:
- 透明:服务器知道本机ip,也知道使用了代理IP
- 匿名:服务器不知道本机IP,但知道代理了IP
- 高匿:服务器不知道代理了IP
高性能异步爬虫
目的:
在爬虫中使用异步实现高性能的数据爬取操作
异步爬虫方式:
- 多线程,多进程(不建议):
好处: 可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步执行
弊端: 无法无限制的开启多线程或者多进程
- 线程池、进程池:(适当的使用)
好处:我们可以降低系统对进程或者线程创建和销毁的评率,从而很好的降低系统
开销
弊端:池中线程或进程的数量是有上限的
单线程+异步协程(推荐):
event_loop:事件循环,相当于一个无线循环,我们可以把一些函数注册到这个事件循环
上,当满足某些条件时,函数就会被循环执行
coroutine:协程对象,我们可以将协程对象注册到事件循环中,他会被事件循环调用。我
们可以使用async关键字来定义一个方法,这个方法在调用时不会立即被执
行,而是返回一个协程对象。
task:任务,他是对协程对象的进一步封装,包含了任务的各个状态
future:代表将来执行或还没有执行的任务,实际上和task没有本质区别
async:定义一个协程
await:用来挂起阻塞方法的执行
selenium模块的基本使用
问题:selenium模块和爬虫之间具有怎样的关联?
- 便捷的获取网站中动态加载的数据
- 便捷实现模拟登陆
什么是selenium模块?
- 基于浏览器自动化的一个模块
selenium使用流程:
- 环境安装:pip install selenium
- 下载一个浏览器的驱动程序
- google下载地址: http://chromedriver.storage.googleapis.com/index.html
- google查看驱动和浏览器版本的映射关系:(最新版本无需查找)
http://blog.csdn.net/huilan_same/article/details/51896672
- 实例化一个浏览器对象
- from selenium import webdriver
- # 实例化一个浏览器对象(传入浏览器驱动)
- bro = webdriver.Chrome(executable_path='./chromedriver')
- 编写基于浏览器自动化的操作代码
- 发起请求:bro.get("http://baidu,com")
- 标签定位:find_element()
- 标签交互:send_keys()
- 执行js程序:execute_script("jsCode")
- 前进、后退:back()、forward()
- 关闭浏览器:quit()
- 获取浏览器当前页面的页面源码数据:page_source
- selenium处理iframe
- 如果定位的标签存在于iframe标签之中,则必须使用switch_to.frame(id)
- 动作链(拖动):from selenium.webdriver import ActionChains(driver)
- 实例化一个动作链对象:action = ActionChains(driver)
- 点击并长按操作:click_and_hold(ele)
- 移动步长:move_by_offset(ele)
- 让动作链立即执行:perform()
- 释放动作链对象:action.release()
HTML基础:
- 所有的元素定位归根结底都是在静态页面的操作下实现的
- HTML叫做标签语言,基于不同的标签来展示不同的内容
- 常见的标签:
- a : 超链接
- img: 图片
- input: 输入框、文件上传、按钮
- iframe: 窗体
- span、div
- HTML标签内容,像变量名称一样是随意的,区分元素的类别主要通过class属性
- 标签包含的属性:
- 标签名称,所有的标签都一定会有标签名
- 属性,单个标签可以有多个属性,只有在<>中的才是属性
- <a>...</a>
- <a/>
- 文本,在<> </>之间的内容,叫做文本
元素定位:
- 提供有八种不同的元素定位方法。在Selenium的实现中,准确来说是有十六种不同的
定位方法。(8中单数,8中复数)
- 八种元素定位:
- id:基于标签的id属性来进行定位,类似于身份证,基本不会重复(可以提前校验
一下)
- name:类似于省份证上的名字,容易重名
- link text:用于定位超链接(a标签)(a标签的文本)
- partial link text:定位a标签,通过模糊查找的形式来定位,类似于mysql中的like
一般会有多元素的结果,一般可以通过find elements来进行定位
- 不加s进行定位,默认返回查找的第一个元素
- 加s进行定位,基于下标的选择返回
- tagname:都是基于复数的s来定位,一般不推荐
- classname :极其不推荐使用
- cssselector:定位届的万金油之一,专治IE浏览器下的元素定位(不支持xpath)
- xpath
- 最为主流的定位方法是xpath,最灵活的定位方法是cssselector、xpath
12306登陆
- 超级鹰:用户登录-超级鹰验证码识别代答题平台
- 注册:普通用户
- 登陆:普通用户
- 题分查询:重置
- 创建一个软件(id)
- 下载示例代码
- 12306模拟登陆编码流程:
- 使用selenium打开登陆界面
- 对当前selenium打开的这张页面进行截图
- 对当前图片局部区域(验证码图片)进行裁剪
- 好处:将验证码图片和模拟登陆进行一一对应(因为图片会刷新)
- 使用超级鹰识别验证码图片(坐标)
scrapy框架
- 什么是框架?
- 就是一个集成了很多功能并且具有很强通用性的一个项目模板
-如何学习框架?
- 专门学习框架封装的各种功能的详细用法
- 什么是scrapy?
- 爬虫中封装好的一个明星框架 。功能:高性能的持久化操作,异步的数据下载,高性
能的数据解析、分布式
- scrapy框架的基本使用
- 环境的安装:
- mac or linux:pip install scrapy
- windows:
- 实测可直接安装
- 创建一个工程:scrapy startproject xxx1
- cd xxx1
- 在spiders子目录中创建一个爬虫文件
- scrapy genspider xxx2 www.xxx.com
- 执行工程:
- scrapy crawl xxx2
- scrapy数据解析
- scrapy持久化存储
- 基于终端指令:
- 指令:scrapy crawl xxx2 -o filepath
- 要求:只可以将parse方法的返回值存储到本地的文本文件中
- 注意:持久化存储对应的文本文件的类型只可以为:'json','jsonlines','jl','csv','xml'
- 好处:简洁高效便捷
- 确定:局限性大(数据只可以存储到指定后缀的文本文件中)
- 基于管道:
- 编码流程:
- 数据解析
- 在item类中定义相关的属性
title = scrapy.Field() content = scrapy.Field()
- 将解析的数据封装存储到item类型的对象
item["title"] = poetry_title item["content"] = poetry_text
- 将item类型的对象提交给管道进行持久化存储的操作
yield item
- 在管道类的process_item中要将其接收到的item对象中存储的数据进行持久
化存储操作
class GushiPipeline: fp = None # 重写其中的一个父类方法:该方法只在开始爬虫的时候被调用一次 def open_spider(self, spider): print('开始打印。。。') self.fp = open('./存储.text', "w", encoding="utf-8") # 专门用来处理item类型对象 # 该方法可以接收爬虫文件提交过来的item对象。 # 该方法每接收到一个item就会被调用一次 def process_item(self, item, spider): title = item["title"] content = item["content"] self.fp.write(title + ":" + content) return item def close_spider(self, spider): print("结束打印!") self.fp.close()
- 在配置文件中开启管道
ITEM_PIPELINES = { 'GuShi.pipelines.GushiPipeline': 300, # 300表示的是优先级,数值越小优先级越高 }
- 好处:通用性强。
面试题:将爬取到的数据一份存储到本地,一份存储到数据库,如何实现?
重点:
- 管道文件中的一个管道类对应的是将数据存储到一种平台
- 爬虫文件提交的item只会给管道文件中第一个被执行的管道类接收
- process_item中的return item表示将item传递给下一个即将被执行的管道类
spiders文件:
import scrapy from GuShi.items import GushiItem class GushiSpider(scrapy.Spider): name = 'gushi' # allowed_domains = ['www.xxx.com'] start_urls = ['https://so.gushiwen.cn/shiwens/'] # 基于终端指令的存储方式 # def parse(self, response): # # 解析:诗词的标题+内容 # # xpath返回的是列表,且列表元素一定是selector类型的对象 # # extract可以将selector对象中的data参数存储的字符串提取出来 # poetry_div_list = response.xpath('.//div[@id="leftZhankai"]//div[@class="sons"]') # content = [] # for poetry in poetry_div_list: # poetry_title = poetry.xpath("./div[1]/p[1]//b/text()")[0].extract() # poetry_text = poetry.xpath("./div[1]/div[2]/text() | ./div[1]/div[2]//p/text()").extract() # poetry_text = ''.join(poetry_text) # dict = {"title": poetry_title, # "content": poetry_text} # content.append(dict) # return content # ============================================================================================ def parse(self, response): poetry_div_list = response.xpath('.//div[@id="leftZhankai"]//div[@class="sons"]') content = [] for poetry in poetry_div_list: poetry_title = poetry.xpath("./div[1]/p[1]//b/text()")[0].extract() poetry_text = poetry.xpath("./div[1]/div[2]/text() | ./div[1]/div[2]//p/text()").extract() poetry_text = ''.join(poetry_text) item = GushiItem() item["title"] = poetry_title.replace(' ', '').strip() + '=====' item["content"] = poetry_text.replace(' ', '').strip() # 将item提交给管道 yield item
items文件
import scrapy class GushiItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() content = scrapy.Field() # pass
piplines文件
# Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html # useful for handling different item types with a single interface from itemadapter import ItemAdapter import pymysql class GushiPipeline(object): fp = None # 重写其中的一个父类方法:该方法只在开始爬虫的时候被调用一次 def open_spider(self, spider): print('开始打印。。。') self.fp = open('./存储.txt', "w", encoding="utf-8") # 专门用来处理item类型对象 # 该方法可以接收爬虫文件提交过来的item对象。 # 该方法每接收到一个item就会被调用一次 def process_item(self, item, spider): title = item["title"] content = item["content"] self.fp.write(title + ":" + content + '\n') # 最好加上return,只有这样优先级高的类才会把item对象传递给下一个即将被执行的管道类 return item def close_spider(self, spider): print("结束打印!") self.fp.close() # 管道文件中一个管道类对应将一组数据存储到一个平台或者载体中 class mysqlPipleLine(object): conn = None cursor = None def open_spider(self,spider): self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='123456',db='test2',charset='utf8') def process_item(self, item, spider): self.cursor = self.conn.cursor() try: self.cursor.execute('insert into python values("%s","%s");' % (item["title"], item["content"])) self.conn.commit() except Exception as e: print(e) print('错误') self.conn.rollback() return item def close_spider(self,spider): self.cursor.close() self.conn.close() # 爬虫文件提交的item类型的对象最终会提交给优先级高的管道类
基于Spider的全站数据爬取
就是将网站中某板块下的全部页码对应的页面数据进行爬取
需求:爬取我要个性网中的照片的名称
实现方式:
- 将所有页面的url添加到start_urls列表(不推荐)
- 自行手动进行请求发送(推荐)
- 手动请求发送:
yield scrapy.Request(url=new_url, callback=self.parse) # callback专门用作数据解析
五大核心组件
请求传参
- 使用场景:如果爬取解析的数据不在同一张页面中。(深度爬取)
- 需求: 爬取我要个性网中图片名称,图片作者名称
import scrapy from tupianPro.items import TupianproItem class Tupian2Spider(scrapy.Spider): name = 'tupian2' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.woyaogexing.com/tupian/dongman/index.html'] url = 'https://www.woyaogexing.com/tupian/dongman/index_%d.html' page_num = 2 # 回调函数接受item def detail_parse(self,response): author = response.xpath('//*[@id="main"]/div[3]/div[1]/div[1]/div[1]/div[1]/div/a/text()').extract_first() print(author) item = response.meta['item'] item['author'] = author yield item # 解析图片名字 def parse(self, response): div_list = response.xpath('//*[@id="main"]/div[3]/div[1]/div[2]/div') for div in div_list: item = TupianproItem() title = div.xpath('./a[2]/text()').extract_first() item['title'] = title print(title) new_url = 'https://www.woyaogexing.com/' + div.xpath('./a[1]/@href').extract_first() # 对详情页发送请求获取详情页源码数据 # 手动请求发送 # 请求传参:meta={},可以将meta字典传递给请求对应的回调函数 yield scrapy.Request(url=new_url, callback=self.detail_parse, meta={'item': item}) # 分页操作 if self.page_num <= 6: new_url = format(self.url % self.page_num) self.page_num += 1 yield scrapy.Request(url=new_url, callback=self.parse)
图片数据爬取值ImagesPipeline
基于scrapy爬取字符串类型的数据和爬取图片类型的数据的区别?
- 字符串:只需要基于xpath进行解析,且提交管道进行持久化存储
- 图片:xpath解析出图片src的属性值。单独的对图片地址发起请求获取图片二进制类型
的数据
ImagesPipeline:
- 只需要将img的src的属性值进行解析,提交到管道,管道就会对图片的src进行请求发
送获取二进制类型的数据,且还会帮我们进行持久化存储
需求: 爬取我要个性网中的图片
使用流程:
- 数据解析(图片的地址)
- 在存储图地址的item提交到制定的管道类
- 在管道文件中自定制一个基于ImagesPipeLine的一个管道类
- get_media_request
- file_path
- item_completed
- 在配置文件中:
- 指定图片存储的目录: IMAGES_STORE = ‘./image_file’
- 指定开启的管道:自定制的管道类
import scrapy from meituPro.items import MeituproItem class MeituSpider(scrapy.Spider): name = 'meitu' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.woyaogexing.com/tupian/dongman/index.html'] url = 'https://www.woyaogexing.com/tupian/dongman/index_%d.html' page_num = 2 def parse(self, response): div_list = response.xpath('//*[@id="main"]/div[3]/div[1]/div[2]/div') for div in div_list: # 如果出现图片懒加载,则需要使用图片的伪属性 src = 'https:' + div.xpath('./a/img/@src').extract_first() print(src) item = MeituproItem() item['src'] = src yield item if self.page_num <= 6: new_url = format(self.url% self.page_num) self.page_num += 1 yield scrapy.Request(url=new_url, callback=self.parse)
# Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class MeituproItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() src = scrapy.Field() # pass
# Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html # useful for handling different item types with a single interface import scrapy from itemadapter import ItemAdapter # class MeituproPipeline(object): # def process_item(self, item, spider): # return item from scrapy.pipelines.images import ImagesPipeline class imagesPipeline(ImagesPipeline): # 根据图片地址进行图片数据的请求 def get_media_requests(self, item, info): yield scrapy.Request(item['src']) # 指定图片存储的路径 def file_path(self, request, response=None, info=None, *, item=None): imgName = request.url.split('/')[-1] return imgName # 返回给下一个即将被执行的管道类 def item_completed(self, results, item, info): return item
# Scrapy settings for meituPro project # # For simplicity, this file contains only settings considered important or # commonly used. You can find more settings consulting the documentation: # # https://docs.scrapy.org/en/latest/topics/settings.html # https://docs.scrapy.org/en/latest/topics/downloader-middleware.html # https://docs.scrapy.org/en/latest/topics/spider-middleware.html BOT_NAME = 'meituPro' SPIDER_MODULES = ['meituPro.spiders'] NEWSPIDER_MODULE = 'meituPro.spiders' # Crawl responsibly by identifying yourself (and your website) on the user-agent USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36' # Obey robots.txt rules ROBOTSTXT_OBEY = False LOG_LEVEL = 'ERROR' # Configure maximum concurrent requests performed by Scrapy (default: 16) #CONCURRENT_REQUESTS = 32 # Configure a delay for requests for the same website (default: 0) # See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay # See also autothrottle settings and docs #DOWNLOAD_DELAY = 3 # The download delay setting will honor only one of: #CONCURRENT_REQUESTS_PER_DOMAIN = 16 #CONCURRENT_REQUESTS_PER_IP = 16 # Disable cookies (enabled by default) #COOKIES_ENABLED = False # Disable Telnet Console (enabled by default) #TELNETCONSOLE_ENABLED = False # Override the default request headers: #DEFAULT_REQUEST_HEADERS = { # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', # 'Accept-Language': 'en', #} # Enable or disable spider middlewares # See https://docs.scrapy.org/en/latest/topics/spider-middleware.html #SPIDER_MIDDLEWARES = { # 'meituPro.middlewares.MeituproSpiderMiddleware': 543, #} # Enable or disable downloader middlewares # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html #DOWNLOADER_MIDDLEWARES = { # 'meituPro.middlewares.MeituproDownloaderMiddleware': 543, #} # Enable or disable extensions # See https://docs.scrapy.org/en/latest/topics/extensions.html #EXTENSIONS = { # 'scrapy.extensions.telnet.TelnetConsole': None, #} # Configure item pipelines # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html ITEM_PIPELINES = { 'meituPro.pipelines.imagesPipeline': 300, } # Enable and configure the AutoThrottle extension (disabled by default) # See https://docs.scrapy.org/en/latest/topics/autothrottle.html #AUTOTHROTTLE_ENABLED = True # The initial download delay #AUTOTHROTTLE_START_DELAY = 5 # The maximum download delay to be set in case of high latencies #AUTOTHROTTLE_MAX_DELAY = 60 # The average number of requests Scrapy should be sending in parallel to # each remote server #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 # Enable showing throttling stats for every response received: #AUTOTHROTTLE_DEBUG = False # Enable and configure HTTP caching (disabled by default) # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings #HTTPCACHE_ENABLED = True #HTTPCACHE_EXPIRATION_SECS = 0 #HTTPCACHE_DIR = 'httpcache' #HTTPCACHE_IGNORE_HTTP_CODES = [] #HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' # Set settings whose default value is deprecated to a future-proof value REQUEST_FINGERPRINTER_IMPLEMENTATION = '2.7' TWISTED_REACTOR = 'twisted.internet.asyncioreactor.AsyncioSelectorReactor' IMAGES_STORE = '../tupian_scrapy/'
中间件
下载中间件
- 位置:引擎和下载器之间
- 作用:批量拦截到整个工程中所有的请求和响应
- 拦截请求:
- UA伪装:process_request
- 代理IP:process_exception:return request
- 拦截响应:
- 篡改响应数据、响应对象
- 需求:爬取网易新闻中的新闻数据(标题和内容)
- 1.通过网易新闻的首页解析出五大板块的详情页的url(没有动态加载)
- 2.每一个板块对应的新闻标题都是动态加载出来的(动态加载)
- 3.通过解析出每一条新闻详情页的url获取详情页的页面源码,解析出内容
CrawlSpider类
- 是Spider的一个子类
- 全站数据爬取的方式
- 基于Spider:手动请求
- 基于CrawlSpider
- CrawlSpider的使用
- 创建一个工程
- cd 新工程
- 创建爬虫文件(CrawlSpider)
- scrapy genspider -t crawl xxx www.xxx.com
- 链接提取器:
- 作用:根据指定的规则进行指定链接的提取
- 规则解析器:
- 作用:将链接提取器提取到的链接进行指定规则(callback)的解析
# 需求:爬取秦楚论坛-十堰城事的帖子标题,帖子内容
- 分析:爬取的数据不在同一页面中
- 1.可以使用链接提取器提取所有页码链接
- 2.让链接提取器提取所有的帖子详情页的链接
分布式爬虫
- 概念: 我们需要搭建一个分布式的机群,让其对一组资源进行分布式联合爬取
- 作用:提升爬取数据的效率
- 如何实现分布式?
- 安装一个scrapy-redis的组件
- 原生的scrapy是不可以实现分布式爬虫的,必须结合scrapy_redis组件一起使用
- 原因:
- 调度器不可以被分布式机群共享
- 管道不可以被分布式机群共享
- scrapy-redis组件作用
- 可以给原生的scrapy框架提供可以被共享的管道和调度器- 实现流程
- 创建一个工程
- 常见一个基于CrawlSpider的爬虫文件
- 修改当前的爬虫文件:
- 导包:from scrapy_redis。spiders import RedisCrawlSpider
- 将start_urls和allowed_domains进行注释
- 添加一个新属性:redis_key = 'sun' 可以被共享的调度器队列的名称
- 编写数据解析相关的操作
- 将当前爬虫类的父类修改为RedisCrawlSpider
- 修改配置文件settings
- 指定可以被共享的管道:
ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline':400 }
- 指定调度器:
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter' # 使用scrapy_redis组件自己的调度器 SCHEDULER = 'scrapy_redis.scheduler.Scheduler' # 配置调度器是否要持久化,也就是爬虫结束了,需不需要清空Redis中请求队列和去重指纹的set SCHEDULER_PERSIST = True
- 指定redis服务器:
# 指定redis # 默认本机:127.0.0.1 # 推荐写远程服务器的ip REDIS_HOST = 'redis服务器的ip地址' REDIS_PORT = 6379
- redis相关操作配置:
- 配置redis的配置文件:
- linux或者mac:redis.conf
- windows:redis.windows.conf
- 打开配置文件进行修改:
- 将bind 172.0.0.1进行删除
- 关闭保护模式:protected-mode yes改为no
- 结合配置文件开启redis服务
- redis-server 配置文件
- 启动客户端:
- redis-cli
- 执行工程:
- scrapy runspider 爬虫文件
- 向调度器的队列中放入一个起始的url:
- 调度器的队列在redis的客户端中
- lpush xxx www.xxx.com
- 爬取到的数据存储在了redis的proName:items这个数据结构中
增量式爬虫
- 概念:检测网站数据更新的情况,只会爬取网站最新更新出来的数据。
- 分析:
- 指定一个起始url
- 基于CrawlSpider获取其他页码链接
- 基于Rule将其他页码链接进行请求
- 从每一个页码对应的源码中解析出每一个电影详情页的url
- 核心:检测电影详情页的url之前有没有请求过- 将爬取过的电影详情页的url存储
- 存储到redis的set数据结构中
- 对详情页的url发起请求,然后解析出电影的名称和简介
- 进行持久化存储