Skip to content

Latest commit

 

History

History
510 lines (336 loc) · 15.8 KB

网络爬虫.md

File metadata and controls

510 lines (336 loc) · 15.8 KB

网络爬虫

一、爬虫的初步了解

1.爬虫的种类
  • 通用爬虫:抓取的的整张页面数据
  • **聚焦爬虫:**建立在通用爬虫的基础,抓取的是页面中的局部内容
  • **增量式爬虫:**检测网站中的数据更新的情况。只会抓取网站中最新更新出来的数据。
2.http和https协议
  • http协议:就是服务器和客户端进行数据交换的一种形式。(或者规范)
    • **常用请求头信息:**User-Agent(请求载体的身份标识)、Connection(请求完毕后,是断开链接还是保持链接)
    • **常用响应头信息:**Content-type:(服务器响应回客户端的数据类型)
  • https协议:安全的http协议(涉及到数据加密)
3.数据加密的方式
  • 对称秘钥加密:服务器给客户端发给数据和对应的秘钥。
  • **非对称秘钥加密:**让服务器端设置一种加密方式(公钥),然后把信息发给客户端(带公钥),客户端利用公钥进行加密,将加密信息传给服务器,服务器使用私钥进行解密。
    • 会影响传输数据速度。
    • 无法保证客户端拿到的秘钥是服务器发送的(可能会被拦截并且篡改)
  • 证书秘钥加密:存在一个证书认证机构(对公钥进行防伪)。

二、requests模块

1.概念:

基于网络请求的模块,功能强大、简单便捷、效率高。作用是模拟浏览器发请求。

2.使用(requests模块的编码流程):
  • 指定url
  • 发起请求
  • 获取响应
  • 持久化存储

三、数据解析方式xpath

1.xpath解析

​ 最常用且高效的一种解析方式,通用性强。

2.解析流程
  • 1.实例化一个etree的对象。且需要将解析的源码数据加载到该对象中。

    • 实例本地化文件

      • from lxml import etree
        etree.parse(filepath) 
    • 实例化网络源码数据

      • etree.HTML('page_text') #page_text = requests.get(url).text
  • 2.调用etree对象中的xpath方法结合这xpath表达式实现标签的定位和内容的捕获

3.xpath表达式
  • / : 表示的是从根节点开始定位,表示一个层级。

  • // : 表示的是多个层级;可以表示从任意位置开始定位。(具体还得了解)

  • 属性定位 :[@属性名称 = “属性值”]

  • 索引定位 :索引是从 1 开始

    r = tree.xpath("//div[@class = "song"]/p[3]")  #定位到class属性为div标签下的第三个p标签
  • 取出标签的文本 :

    • /text( )方法 ,返回一个列表 ,只能获得标签的直系文本
    • //text( )方法,返回一个列表,可以获取该标签下的所有文本
  • 取出标签中的属性:/@[属性值]

    img_url = tree.xpath("//div/img/@src")
    4.处理中文乱码的问题
    #对全部页码进行更改格式
    page_text.encoding = "utf-8"
    
    #先编码再解码
    string.encode("iso-8859-1").decode('gbk')  

四、验证码的处理

1.利用第三方平台进行验证码的处理
  • 云打码(网站好像没了)
2.超级鹰

五、cookie的操作

1.cookie:服务端创建,存储在客户端,服务器端记录客户端的相关信息。 (http/https是无状态的)
2.实现方法
  • 手动处理:通过抓包工具(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反爬机制

1.代理:代理服务器。本机-代理服务器-目标服务器
  • 突破自身IP访问的限制
  • 隐藏自身真实的IP
2.代理相关网站
  • 快代理
  • 西祠代理
  • www.goubanjia.com
  • 代理ip的匿名度
    • 透明:服务器知道本次请求使用了代理,也知道请求对应的真实ip
    • 匿名:知道使用了代理,但是不知道真实ip
    • 高匿:不知道使用了代理,更不知道真实的ip

七、异步爬虫(提升爬取效率)

1.多线程和多进程(但是不建议)

好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步执行。

坏处:无法无限制的开启多线程后者多线程。

2.进程池和线程池

好处:可以降低系统对线程或者进程的创建和销毁的效率, 从而很好的降低系统的开销

坏处:池中线程或者线程的数量是有上限的。

3.线程池类multiprocessing

处理的是阻塞并且耗时的操作

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)
4.单线程+异步协程(推荐方法)
1.协程(python3.4才出现)

八、selenium

1.selenium作用
  • 便捷的获取网站中动态加载的数据(ajax方法不变的时候)
  • 便捷实现模拟登录
2.selenium是什么

​ 基于浏览器起自动化的一个模块。

3.selenium的基本使用
4.iframe(网页中的子页面)
  • iframe也是从<html></html>开始的

  • 定位的标签如果在iframe中,则必须通过如下操作在进行标签定位

    #切换浏览器标签定位的作用域
    browser.switch_to.frame(目标子页面的id)
    div = browser.find_element_by_id()
5.动作链(ActionChains)
  • 导入动作链的类

    from selenium.Chrome import ActionChains
  • 实例化

    action = ActionChains(browser)
  • 开始操作

    # 点击长按指定的标签
    action.click_and_hold(定位到的元素)
    # 拖动 perform()代表立刻执行动作链
    action.move_by_offset(X,Y).perform()
  • 释放动作链

    action.release()
6.让浏览器无可视化界面
  • 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框架

1.基本使用流程
  • scrapy startproject 项目名称

  • cd 到工程文件

  • 在spiders 子目录中创建一个爬虫文件:scrapy genspider spiderName www.xxx.com

  • 执行工程:scrapy crawl spiderName

    • scrapy crawl spiderName -nolog 不显示日志信息

    • 在settings.py加一行设置

      # 显示指定类型的日志信息
      LOG_LEVEL = "ERROR"
2.源码解析
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()可以将列表中的文本转换成字符串
3.五大组件
  • 引擎scrapy
    • 用于处理整个系统的数据流处理,触发事务(框架核心)
  • 调度器Scheduler
    • 用于接受引擎发送过来的请求,压入队列中,并在引擎再次请求的时候返回,可想象成一个一个url(抓取网页的网址或者说是链接)
  • 下载器(downloader)
    • 用于下载网页内容,并将网页内容返回引擎(scrapy下载器是建立在twisted这个高效的异步模型上的)
  • 爬虫(Spiders)
    • 爬虫主要是干活的,用于从特定的网页中提取自己需要的信息,即所谓的实体(Item)。用户也可以从中提取信息,用户也可以从中提取出链接,让Scrapy继续抓取下一个页面。
  • 项目管道(Pipline)
    • 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清楚不需要的信息。当前页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
4.持久化存储
  • 基于终端指令

    • 只可以将parse方法的返回值存储到本地的文本文件中
    • scrapy crawl [爬虫Name] -o [filepath]
    • 支持数据类型有限,如json、csv等,但不支持txt
  • 基于管道

    编码流程:

    • 数据解析
    • 在item类中定义相关的属性,在items.py中,author = scrapy.Field( )
    • 将解析的数据类型封装存储到item类型的对象中
    • 将item类型的对象提交给管道进行持久化存储的操作
    • 在管道类的process_item中将其接受到的item对象中存储的数据进行持久化存储的操作
    • 在配置文件中开启管道
5.请求传参

应用场景:解析的数据不在一张页面中(深度爬取)

代码案例:

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)
            
	
6.图片数据爬取之ImagPipeline

基于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"
    • 指定开启的管道:自定制的管道类

7.中间件(下载中间件和爬虫中间件)
  • 下载中间件:引擎和下载器之间(可以批量拦截所有的请求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)
  • 爬虫中间件:爬虫和引擎之间

十、分布式爬虫

1.如何实现分布式爬虫
  • 原生的scrapy不能实现分布式爬虫,必须让scrapy结合着scrapy-redis实现