- 通用爬虫:抓取的的整张页面数据
- **聚焦爬虫:**建立在通用爬虫的基础,抓取的是页面中的局部内容
- **增量式爬虫:**检测网站中的数据更新的情况。只会抓取网站中最新更新出来的数据。
- http协议:就是服务器和客户端进行数据交换的一种形式。(或者规范)
- **常用请求头信息:**User-Agent(请求载体的身份标识)、Connection(请求完毕后,是断开链接还是保持链接)
- **常用响应头信息:**Content-type:(服务器响应回客户端的数据类型)
- https协议:安全的http协议(涉及到数据加密)
- 对称秘钥加密:服务器给客户端发给数据和对应的秘钥。
- **非对称秘钥加密:**让服务器端设置一种加密方式(公钥),然后把信息发给客户端(带公钥),客户端利用公钥进行加密,将加密信息传给服务器,服务器使用私钥进行解密。
- 会影响传输数据速度。
- 无法保证客户端拿到的秘钥是服务器发送的(可能会被拦截并且篡改)
- 证书秘钥加密:存在一个证书认证机构(对公钥进行防伪)。
基于网络请求的模块,功能强大、简单便捷、效率高。作用是模拟浏览器发请求。
- 指定url
- 发起请求
- 获取响应
- 持久化存储
最常用且高效的一种解析方式,通用性强。
-
1.实例化一个etree的对象。且需要将解析的源码数据加载到该对象中。
-
实例本地化文件
-
from lxml import etree etree.parse(filepath)
-
-
实例化网络源码数据
-
etree.HTML('page_text') #page_text = requests.get(url).text
-
-
-
2.调用etree对象中的xpath方法结合这xpath表达式实现标签的定位和内容的捕获
-
/ : 表示的是从根节点开始定位,表示一个层级。
-
// : 表示的是多个层级;可以表示从任意位置开始定位。(具体还得了解)
-
属性定位 :[@属性名称 = “属性值”]
-
索引定位 :索引是从 1 开始
r = tree.xpath("//div[@class = "song"]/p[3]") #定位到class属性为div标签下的第三个p标签
-
取出标签的文本 :
- /text( )方法 ,返回一个列表 ,只能获得标签的直系文本
- //text( )方法,返回一个列表,可以获取该标签下的所有文本
-
取出标签中的属性:/@[属性值]
img_url = tree.xpath("//div/img/@src")
#对全部页码进行更改格式 page_text.encoding = "utf-8" #先编码再解码 string.encode("iso-8859-1").decode('gbk')
- 云打码(网站好像没了)
-
手动处理:通过抓包工具(F12)获得,然后将该值封装到headers中
-
自动处理
-
cookie来自哪里:模拟登录post请求后,由服务端创建
-
session会话对象
- 1.进行请求的发送
- 2.如果请求过程中产生了cookie,则该cookie会被自动存储到该session对象中。
-
具体操作
-
创建一个session对象(session = requsests.Session())
-
使用session对象进行模拟登录post请求的发送(cookie就会被存储到session中)
response = session.post(url = url,headers = headers,data = data)
-
session对象对个人主页对应的get请求进行发送(携带了cookie)
page_text = session.get(url = url,headers = headers).text
-
-
- 突破自身IP访问的限制
- 隐藏自身真实的IP
- 快代理
- 西祠代理
- www.goubanjia.com
- 代理ip的匿名度
- 透明:服务器知道本次请求使用了代理,也知道请求对应的真实ip
- 匿名:知道使用了代理,但是不知道真实ip
- 高匿:不知道使用了代理,更不知道真实的ip
好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步执行。
坏处:无法无限制的开启多线程后者多线程。
好处:可以降低系统对线程或者进程的创建和销毁的效率, 从而很好的降低系统的开销
坏处:池中线程或者线程的数量是有上限的。
处理的是阻塞并且耗时的操作
import time
from multiprocessing.dummy import Pool
start_time = time.time()
name_list = ['xiaosi','aa','bb','cc']
def get_page(str):
print("正在下载:",str)
time.sleep(2)
print("下载成功:",str)
#实例化一个线程池对象
pool = Pool(4)
#列表中的每一个列表元素都传递给get_page处理
pool.map(get_page,name_list)
end_time = time.time()
pool.close()
pool.join()
print(end_time - start_time)
- 便捷的获取网站中动态加载的数据(ajax方法不变的时候)
- 便捷实现模拟登录
基于浏览器起自动化的一个模块。
-
iframe也是从<html></html>开始的
-
定位的标签如果在iframe中,则必须通过如下操作在进行标签定位
#切换浏览器标签定位的作用域 browser.switch_to.frame(目标子页面的id) div = browser.find_element_by_id()
-
导入动作链的类
from selenium.Chrome import ActionChains
-
实例化
action = ActionChains(browser)
-
开始操作
# 点击长按指定的标签 action.click_and_hold(定位到的元素) # 拖动 perform()代表立刻执行动作链 action.move_by_offset(X,Y).perform()
-
释放动作链
action.release()
- PhantomJs已经停止更新和维护,建议使用google的无头浏览器,使用selenium的一个类实现
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headerless')
chrome_options.add_argument('--disable-gpu')
-
规避检测
在启动chrome之前,设置Chromedriver的启动参数,开启实验性功能参数,excludeSwitches,它的值为['enable-automation'],完成代码:
from selenium.webdriver import Chrome
from selenium.webdriver import ChromeOptions
option = ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
driver = Chrome(options=option)
-
scrapy startproject 项目名称
-
cd 到工程文件
-
在spiders 子目录中创建一个爬虫文件:scrapy genspider spiderName www.xxx.com
-
执行工程:scrapy crawl spiderName
-
scrapy crawl spiderName -nolog 不显示日志信息
-
在settings.py加一行设置
# 显示指定类型的日志信息 LOG_LEVEL = "ERROR"
-
import scrapy
class FirstSpider(scrapy.Spider):
# 爬虫文件的名称:就是爬虫源文件的唯一标识符
name = 'first'
# 允许的域名,用来限定start_urls列表中哪些url可以进行请求发送
allowed_domains = ['www.xx.com']
#其实的url列表:该列表里面存放的url会被scrapy自动进行请求的发送
start_urls = ['http://www.xx.com/']
# 用作数据解析,response参数表示的是请求成功对应的响应对象
def parse(self, response):
response.xpath('') # 和xpath方法基本一样
# xpath返回的是列表,但列表元素一定是Selector类型的对象
# extract()可以将Selector对象中data参数存储的字符串提取出来
# ''.join()可以将列表中的文本转换成字符串
- 引擎scrapy
- 用于处理整个系统的数据流处理,触发事务(框架核心)
- 调度器Scheduler
- 用于接受引擎发送过来的请求,压入队列中,并在引擎再次请求的时候返回,可想象成一个一个url(抓取网页的网址或者说是链接)
- 下载器(downloader)
- 用于下载网页内容,并将网页内容返回引擎(scrapy下载器是建立在twisted这个高效的异步模型上的)
- 爬虫(Spiders)
- 爬虫主要是干活的,用于从特定的网页中提取自己需要的信息,即所谓的实体(Item)。用户也可以从中提取信息,用户也可以从中提取出链接,让Scrapy继续抓取下一个页面。
- 项目管道(Pipline)
- 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清楚不需要的信息。当前页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
-
基于终端指令
- 只可以将parse方法的返回值存储到本地的文本文件中
- scrapy crawl [爬虫Name] -o [filepath]
- 支持数据类型有限,如json、csv等,但不支持txt
-
基于管道
编码流程:
- 数据解析
- 在item类中定义相关的属性,在items.py中,author = scrapy.Field( )
- 将解析的数据类型封装存储到item类型的对象中
- 将item类型的对象提交给管道进行持久化存储的操作
- 在管道类的process_item中将其接受到的item对象中存储的数据进行持久化存储的操作
- 在配置文件中开启管道
应用场景:解析的数据不在一张页面中(深度爬取)
代码案例:
import scrapy
from bossPro.itmes import BossproItem
class XiaohuaSpider(scrapy.Spider):
name = 'xiaoHua'
#allowed_domains = ['www.xxx.com']
start_urls = ['http://www.xxx.com/'] # 初始网址
page_num = 2
url = "https://www.zhipin.com/xxxxx%d"
def parse_detail(self,response):
# 将请求传参的字典类型进行接受
item = response.meta['item']
job_desc = resposne.xpath('xxxxx')
job_desc = ''.join(job_desc)
item['job_desc'] = job_desc
def parse(self, response):
li_list = response.xpath('xxxx')
for li in li_list:
# 初始化一个Item类
item = BossproItem()
# 工作名称在初始页面上
job_name = li.xpath('xxxx').extract()
# 将数据保存在Item中
item['job_name'] = job_name
# 具体的招聘信息不在初始页面上,在下边的detail_url里面
detail_rul = 'https://www.zhipin.com' + li.xpath('xxxx')
#进行手动请求的发送
#meta参数将itme对象传给请求对应的回调函数,这既是请求传参
yeild scrapy.Request(detail_url,callback=self.pase_detail,meta = {'item':item})
#进行分页操作
if page_num <= 3:
new_url = format(self.url%self.page_num)
self.page_num += 1
yield scrapy(new_url,callback = self.parse)
基于scrapy爬取字符串类型的数据和爬取图片类型的数据有什么区别呢?
- 字符串:只需要基于xpath进行解析且提交管道进行持久化存储
- 图片:xpath解析出图片src的属性值。单独对图片地址发起请求获取图片的二进制的数据
ImagePipeline怎么用
-
只需要将img的src属性进行解析,提交给管道,管道就会对图片的src进行请求发送获取的二进制数据,然后持久化存储(很方便)
-
使用流程:
-
在管道文件中自制一个基于ImagesPipeLine的管道类
- -get_media_request
- -file_path
- -item_completed
from scrapy.pipelines.images import ImagePipeline import scrapy class ImgPipeLine(ImagePipline): #对item中的图片进行请求操作 def get_media_request(self,item,info): yield scrapy.Request(item['src']) # 定制图片的保存地址及名称 def file_path(self,request,response = None,info = None): img_name = request.url.split('/')[-1] return img_name def item_completed(self,results,item,info): return item # 返回给下一个即将被执行的管道类
-
在配置文件中:
- 指定图片的存储目录:IMAGES_STORE = "filepath"
-
指定开启的管道:自定制的管道类
-
- 下载中间件:引擎和下载器之间(可以批量拦截所有的请求url,也可以拦截到所有的响应对象),需要在settings.py进行手动开启
- 拦截请求:
- UA伪装(可以设置成尽可能多不同的UA)区别于配置文件的全局UA。process_request( )
- 代理IP,process_exception( ) return request
- 拦截响应:
- 篡改响应数据,响应数据(针对动态加载的问题)
- 拦截请求:
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
# 拦截请求(修改的UA请求放在这里)
def process_request(self, request, spider):
# User_Agent_list中选中一个
request.headers['User-Agent'] = random.choice(self.user_agent_list)
return None
# 拦截所有的响应
def process_response(self, request, response, spider):
return response
# 拦截异常的请求
def process_exception(self, request, exception, spider):
# Called when a download handler or a process_request()
# (from other downloader middleware) raises an exception.
if request.url.split(':')[0] == 'http':
request.meta['proxy'] = 'http://' + random.choice(self.PROXY_http)
else:
request.meta['proxy'] = 'https://' + random.choice(self.PROXY_https)
return request # 将修正之后的请求对象进行重新请求发送
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
- 爬虫中间件:爬虫和引擎之间
- 原生的scrapy不能实现分布式爬虫,必须让scrapy结合着scrapy-redis实现