《网络爬虫开发实战案例》笔记

转自行云博客https://www.xy586.top/

爬虫基础

1.HTTP基本原理

URI和URL

URI: 统一资源标志符

URL: 统一资源定位符

HTTP和HTTPS

HTTP: 超文本传输协议,用于从网络传输超文本数据到本地浏览器的传输协议,它能够保证高效准确的传输文本文档

HTTPS: 以安全为目标的HTTP通道,简单来讲是HTTP的安全版,即HTTP下加入SSL,所简称为HTTPS

HTTPS的安全基础是SSL,因此通过它传输的内容都是经过SSL加密的,它的主要作用可以分为两种:

  1. 建立一个信息安全通道来保证数据传输的安全
  2. 确认网站的安全性,凡是使用HTTPS的网站,都可以通过点击浏览器地址栏的锁头标志来查看网站认证的真实信息

HTTP请求过程

  • 第一列name: 请求的名称,一般会将URL的最后一部分当作名称

  • 第二列status: 响应的状态码

  • 第三列type: 请求的文档信息

  • 第四列initiator: 请求源,用来标记请求是由哪个对象或者进程发起的

  • 第五列size: 从服务器下载的文件和请求的资源大小,如果是从缓存中取得的资源,则该列会显示 from cache

  • 第六列time: 发起请求到获取响应所用的总时间

  • 第七列waterfall: 网络请求的可视化瀑布流

请求

请求,由客户端向服务端发出,可以分为四个部分内容:请求方法、请求的网址,请求头,请求体

  1. 请求方法: 常见的请求方法有两种:GET 和 POST

    GET 和POST 请求方法有如下区别:

    • GET请求的参数包含在URL里面,数据可以在URL中看到,而POST请求的URL不会包含这些数据,数据都是通过表单形式传输的,会包含在请求体中
    • GET请求提交的数据最多只有1024字节,而POST方式没有限制
  2. 请求的网址: URL

  3. 请求头:

    • Accept: 请求报头域,用于指定客户端可接受哪些类型的信息

    • Accept-Language: 指定客户端可接受的语言类型

    • Accept-Encoding: 指定客户端可接受的语言类型

    • Host: 用于指定请求资源的主机 IP 和 端口号,其内容为请求URL 的原始服务器或者网关的位置

    • Cookie: 这是网站为了辨别用户进行会话跟踪而存储在用户本地的数据,他的主要功能就是维持当前访问会话,例如,我们输入用户名和密码成功登录某个网 站后,服务器会用会话保存登录状态信息,后面我们每次刷新或请求该站点的其他页面时, 会发现都是登录状态,这就是 Cookies 的功劳。Cookies 里有信息标识了我们所对应的服务器 的会话,每次浏览器在请求该站点的页面时,都会在请求头中加上 Cookies 并将其发送给服

      务器,服务器通过 Cookies 识别出是我们自己,并且查出当前状态是登录状态,所以返回结 果就是登录之后才能看到的网页内容

    • Referer: 此内容来标识这个请求是从哪个页面发过来的,服务器可以拿到这一信息并做相应的处理,如做来源统计、防盗链处理

    • User-Agent: 简称UA ,他是一个特殊的字符串,可以使服务器识别客户使用的操作系统及版本,浏览器即版本信息,在做爬虫时加上此信息,可以伪装为浏览器,如果不加,很可能会被识别为爬虫

    • Content-Type: 也叫互联网媒体类型,在HTTP协议消息头中,它用来表示具体请求的媒体类信息,例如text/html 代表HTML格式 、application/json 代表 JSON 类型

      因此,请求头是请求的重要组成部分,再写爬虫时,大部分情况下都需要设定请求头

  4. 请求体

    请求体一般承载的内容是POST请求中的表单数据,而对于GET请求,请求体为空

    在爬虫中,如果要构造POST请求需要使用正确的Content-Type。并了解各种请求库的各个参数设置时使用的是哪种Content-Type,不然可能会导致POSt提交后无法正常响应

响应

响应,由服务器端返回给客户端,可以分为但部分:响应状态码、响应头、响应体

  1. 响应状态码

    状态码 描述
    200 服务器正常响应
    404 页面未找到
    500 服务器内部发生错误
  2. 响应头

    响应头包含了服务器对请求的应答信息,如Content-Type、Server、Set-Cookie

    • Date: 标识响应产生的时间
    • Last-Modified: 指定资源的最后修改时间
    • Content-Encoding: 指定响应内容的编码
    • Server: 包含服务器的信息,比如名称、版本号
    • Content-Type: 文档类型,代表返回的数据类型是什么
    • Set-Cookie: 设置Cookies 响应头中的Set-Cookie 告诉浏览器需要将此内容放在Cookies中,下次请求携带Cookies
    • expires: 指定响应的过期时间,可以使代理服务器或浏览器将加载的内容跟新到缓存中,如果再次访问时,就可以直接从缓存中加载,降低服务器负载,缩短加载时间
  3. 响应体

    最重要的就是响应体,响应的正文数据都在响应体中

2.网页基础

网页的组成

  • HTML: 超文本标记语言

  • CSS: 层叠样式表,样式指网页中文字大小、颜色、元素间距、排列等格式

  • JavaScript: 脚本语言,时用户与信息之间不只是一种浏览与显示的关系,而是实现了一种实时、动态、交互的页面功能

    综上所述,HTML定义了网页的内容和结构,CSS描述了网页的布局,JS定义了网页的行为

网页的结构

  • 节点树及节点间的关系:

    在HTML中,所有标签定义的内容都是节点,他们构成了一个HTML DOM 树

    DOM: 文档对象模型,它允许程序和脚本动态的访问和更新文档的内容、结构、样式

  • 选择器:

爬虫的基本原理

​ 我们可以把互联网比作一张大网,而爬虫便是在网上爬行的蜘蛛,把网的节点比作一个个网页,爬虫爬到这就相当于访问了该页面,获取了其信息,可以把节点之间的连线比作网页与网页之间的连接关系,这样蜘蛛通过一个节点,可以顺着节点连线继续爬到下一个节点,网站的数据就可以被抓取下来了

  • 爬虫概述:

    1. 获取网页
    2. 提取信息
    3. 保存数据
    4. 自动化程序
  • JavaScript渲染页面:

    有时候我们在用urllib 或 requests 抓取网页时,得到的源代码实际和浏览器中看到的不一样,但是在用 lib request 等库请求当前页面时,我们得到的只是这个 HTML 码,它不会帮助 我们去继续加载这个 JavaScript 文件,这样也就看不到浏览器中的内容了,因此,使用基本 HTTP 请求库得到的源代码可能跟浏览器中的页面源代码不太一样 对于这样的情 况,我们可以分析其后台 Ajax 接口,也可使用 Se nium Splash 这样的库来实现模拟 JavaScript 渲染

会话的基本原理

  • 无状态HTTP

    HTTP协议对事务处理是没有记忆功能的,也就是说服务器不知道客户端是什么状态。

    这时两个用于保持 HTTP 接状态的技术就出现了,它 分别是会话和 Cookies 会话在服务端。

    也就是网站的服务器,用来保存用户的会话信息; Cookies 在客户端,也可以理解为浏览器端,有

    Cookies ,浏览器在下次访问网页时会自动附带上它发送给服务器,服务器通过识别 Cookjes 并鉴定出

    是哪个用户,然后再判断用户是否是登录状态,然后返回对应的响应。

    我们可以理解为 Cookies 里面保存了登录的凭证,有了它,只需要在下次请求携带 Cookies 发送

    请求而不必重新输入用户名、密码等信息重新登录了。

    因此在爬虫中,有 候处理需要登录才能访问的页面时,我们一般会直接将登录成功后获取的

    Cookies 放在请求头里面直接请求,而不必重新模拟登录。

  • 属性结构

    • name: Cookie的名称,一旦创建,该名称便不可更改
    • value: 改Cookie的值,如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64 编码
    • domain: 可以访问改Cookie的域名,例如,如果设置为.zhihu.com ,则所有以 zhihu.com 结尾的域名都可以访问该Cookie
    • Max Age: 该Cookie失效的时间
    • path: 该Cookie 的使用路径,如果设置为 /,则本域名下的所有页面都可以访问该Cookie
  • 会话 Cookie 和持久 Cookie

    从表面意思来说,会话 Cookie 就是把 Cookie 放在浏览器内存里,浏览器在关闭之后该 Cookie 失效 持久 Cookie 会保存到客户端的硬盘中,下次还可以继续使用,用于长久保持用户登录状态 其实严格来说,没有会话 Cookie 和持久 Cookie 分,只是由 ookie Max Age Expires 字段 决定了过期的时间

代理的基本原理

我们在做爬虫的过程巾经常会遇到这样的情况 最初爬虫正常运行,正常抓取数据,一切看起来 都是那么美好,然 杯茶的功夫可能就 出现错误,比如 403 Forbidden 这时候打开网页一看 ,可 能会看到“您的 IP 访问频率太高”这样的提示 出现这种现象的原因是网站采取了一些反爬虫措施 比如,服务器会检测某个 IP 在单位时间内的请求次数,如果超过了这个阔值,就会直接拒绝服务,返 问一些错误信息,这种情况可以称为封 IP,既然服务 检测的是某个 IP 单位时间的请求次数,那么借助某种方式来伪装我们的 IP ,让服 器识别不出是由我们本机发起的请求

  • 代理的作用:

    1. 突破自身IP的访问限制,访问一些平时不能访问的站点
    2. 访问一些单位或团体内部资源:比如使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享服务
    3. 提高访问速度,通常代理服务器都设置一个较大的硬盘缓冲区,当外界的信息通过时,同时也将其保存到缓冲区中,当其他用户在访问相同的信息时,则直接由缓冲区取出信息,传给用户,以提高访问速度
    4. 隐藏真实的IP,上网者也可以通过这种方式隐藏自己的IP,免受攻击,对于爬虫来说,我们用代理就是为了隐藏自身IP,防止自身的IP被封锁
  • 爬虫代理

    对于爬虫来说,由于爬虫爬取速度过快,在爬取过程中可能遇到同 IP 访问过于频繁的问题,

    此时网站就会让我们输入验证码登录或者直接封锁 ,这样会给爬取带来极大的不便

    使用代理隐藏真实的 IP ,让服务器误以为是代理服务器在请求向自己 这样在爬取过程中通过不断

    更换代理,就不会被封锁,可以达到很好的爬取效果

  • 代理分类

    1. 根据协议区分
      • FTP代理服务器,主要用于访问FTP服务器,一般有上传、下载、缓存功能,端口一般为 21 、2121 等
      • HTTP 代理服务器:主要用于访问网页,一般有内容过滤和缓存功能,端口一般为 80 、8080、3128
      • SSL/TLS:主要用于访问加密网站,一般有SSL 或者 TLS 加密功能(最高支持128位加密强度),端口一般为443
      • RTSP代理:主要用于访问Real流媒体服务器,一般有缓存功能,一般端口为554
      • Telnet代理:主要用于telnet 远程控制(黑客入侵计算机时常用于隐藏身份),端口一般为23
      • POP3/SMTOP代理:主要用于POP3/SMTP方式收发邮件,一般有缓存功能,端口一般为110、25
      • SOCKS代理:只是单纯传递数据包。不关心具体协议和用法,所有速度很快,端口一般为1080
    2. 根据匿名程度区分
      • 高度匿名代理:会将数据包原封不动的转发,在服务器看来就好像是一个真正的普通客户端在访问,而记录的IP是代理服务器的IP
      • 普通匿名代理:会在数据包上做一些改动,服务端有可能发现这是个代理服务器,也有一定几率追查到客户端的真实IP
      • 透明代理:不但改动了数据包,还会告诉服务器客户端的真实IP,这种代理除了能用缓存技术提高浏览速度,能用内容过滤提高安全性能之外,并无其他显著作用,最常见的例子就是内网中的硬件防火墙
  • 常见的代理设置

    • 使用网上的免费代理: 最好使用高匿名代理,另外可用的代理不多,需要在使用前筛选一下可用代理,也可以进一步维护一个代理池
    • 使用付费代理服务: 质量比免费代理还很多
    • ADSL拨号: 播一次号换一次IP ,稳定性高,也是一种比较有效的解决方案

3.requests库的基本使用

基本用法

  • GET请求:

    import requests
    r = requests.get(’http://httpbin.org/get‘)
    
    """
    输出结果:
    {
      "args": {}, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.22.0"
      }, 
      "origin": "220.202.133.149, 220.202.133.149", 
      "url": "https://httpbin.org/get"
    }
    """
    

    r . json()方法:将返回的结果是JSON格式的字符串转为一个字典格式

    一般要在headers上加上User-Agent信息

    headers = {
         
                  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36"
              }
    
  • POST请求:

    import requests
    data = {
         
        'name':'donmo',
        'age' : 20
    }
    r = requests.post('http://httpbin.org/post',data = data)
    print(r.text)
    
    """
    {
      "args": {}, 
      "data": "", 
      "files": {}, 
      "form": {
        "age": "20", 
        "name": "donmo"
      }, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Content-Length": "17", 
        "Content-Type": "application/x-www-form-urlencoded", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.22.0"
      }, 
      "json": null, 
      "origin": "220.202.133.149, 220.202.133.149", 
      "url": "https://httpbin.org/post"
    }
    我们可以成功获取返回结果,其中form部分就是提交的数据,这就证明了post请求成功发送了
    """
    
    
  • 响应

    import requests
    headers = {
         
                  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36"
              }
    r = requests.get('https://www.jianshu.com/',headers = headers)
    print(type(r.status_code))
    print(type(r.headers))
    print(type(r.cookies))
    print(type(r.url))
    print(type(r.history))
    
    """
    <class 'int'>
    <class 'requests.structures.CaseInsensitiveDict'>
    <class 'requests.cookies.RequestsCookieJar'>
    <class 'str'>
    <class 'list'>
    """
    

高级用法

  1. 文件上传:

    我们可以知道requests可以模拟提交一些数据,假如有的网站需要上传文件,我们也可以用它来实现

    import requests
    files = {
         
        'file':open('爬取的资源/favicon.ico','rb')
    }
    r = requests.post('http://httpbin.org/post',files = files)
    print(r.text)
    
    """
    {
      "args": {}, 
      "data": "", 
      "files": {
        "file": "data:application/octet-........
      }, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Content-Length": "6665", 
        "Content-Type": "multipart/form-data; boundary=bcf321b8c23ed3ffec5c8c2ea30f3c40", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.22.0"
      }, 
      "json": null, 
      "origin": "220.202.133.149, 220.202.133.149", 
      "url": "https://httpbin.org/post"
    }
    里面包含 files 这个字段,而 form 字段是 的,这证明文件上传部分会单独有一个 files 字段来标识
    
    """
    
  2. Cookies

    import requests
    r = requests.get('https://www.baidu.com')
    print(r.cookies)
    for key,value in r.cookies.items():
        print(key + "=" + value)
        
    """
    <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
    BDORZ=27315
    
    这里我们首先调用 Cookies 属性即可成功得到 Cookies 可以发现它 RequestCookiJar 类型
    然后 items()方法将其转为元组组成的列表  遍历输出每一个 Cookie 名称和值  实现Cookie
    的遍历解析
    """
    
  3. 会话维持

  4. 代理设置

正则表达式

模式 描述
\w 匹配字母,数字及下划线
\W 匹配不是字母,数字及下划线
\s 匹配任意空白字符,等价于【\t \n \r\ \f】
\S 匹配任意非空字符
\d 匹配任意数子 等价于【0-9】
\D 匹配任意非数字的字符
\A 匹配字符串开头
\Z 匹配字符串结尾,如果存在换行,只匹配换行前的结束字符
\z 匹配字符串结尾,如果存在换行,同时还会匹配换行符
\G 匹配最后完成匹配的位置
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配一行字符串的开头
$ 匹配一行字符串的结尾
. 匹配任意字符,除了换行
[…] 用来表示一组字符,单独列出,比如[amk] 匹配a、m、或 k
[^…] 不在[ ]中的字符
* 匹配0 个 或多个表达式
+ 匹配一个或多个表达式
匹配 0 个或 1 个前面的正则表达式定义的片段,非贪婪方式
{n} 精确匹配 n 个前面的表达式
{n,m} 匹配 n 到 m 次由前面正则表达式定义的片段,贪婪方式
a|b 匹配 a 或 b
( ) 匹配括号内的表达式,也表示一个组
  • match(): 向他传入要匹配的字符串以及正则表达式,从字符串的开头开始匹配
  • 贪婪匹配:尽可能匹配多得字符
  • 非贪婪匹配:尽可能匹配少的字符
  • search(): 扫描整个字符串,然后返回第一个成功匹配的结果
  • findall(): 该方法会搜索整个字符串,然后返回匹配正则表达式的所有内容,有结果就是列表类型
  • sub(): 可以借助他来修改文本,第一个参数传入匹配的内容,第二个参数为替换的字符串,第三参数是原字符串
  • compile(): 将正则字符串编译成正则表达式对象,以便在后面的匹配中复用

4.解析库的使用

使用XPath

XPath:全称XML Path Language ,即XML 路径语言,是一门在XML 文档中查找信息的语言

官网:[https://www.w3.org/TR/xpath/]( XPath 官方文档)

  1. XPath 概览: 几乎所有我们想要定位的节点,都可以用XPath 来选择

  2. XPath 常用规则:

    表达式 描述
    nodename 选取此节点的所有子节点
    / 从当前节点选取直接子节点
    // 从当前节点选取子孙节点
    . 选取当前节点
    选取当前节点的父节点
    @ 选取属性
  3. XPath 常用匹配规则:

    //title[@lang = ‘eng’] : 代表选择所有名称为 title,同时属性 lang 的值为 eng 的节点

  4. 实例引入:

    from lxml import etree
    text = ' html .....'
    html = etree.HTML(text)
    result = etree.tostring(html)  # 这结果是btyes 类型 可以利用decode('utf-8') 转成str 类型
    
    • # 也可以直接读取文本文件进行解析
      from lxml import etree
      html = etree.parse('./test.html',etree.HTMLParse())
      result = etree.tostring(html)
      
  5. 文本的获取: text()

  6. 属性值多匹配: contains() 函数

    from lxml import etree
    text = '<li class = "li li-list">...</li>'
    html = etree.HTML(text)
    result = html.xpath('//li[contains(@class,"li")]')
    
  7. 多属性匹配: 根据多个属性确定一个节点,这时就需要同时匹配多个属性,此时可以使用 and 来连接

    from lxml import etree
    text = '<li class = "li li-list" name = "item">...</li>'
    html = etree.HTML(text)
    result = html.xpath('//li[contains(@class,"li") and @name = "item"]')
    
  8. 按序选择: 我们在选择的时候可能同时匹配了多个节点,但只想要其中的某个节点

    result1 = html.xpath('//li[1]')  #选取第一个li 节点    li[1]
    result2 = html.xpath('//li[last()]')  #选取最后一个 li 节点   last()
    result3 = html.xpath('//li[position()<3]')  #选取位置小于3 的li 节点 也就1 2 节点  position()<3
    result4 = html.xpath('//li[last() - 2]')  #选取倒数第三个 li 节点  last() -2
    
  9. 节点轴选择:

    轴名称 描述
    //li[1]/ancestor:😗 匹配第一个li 节点的所有祖先节点
    //li[1]/ancestor::div 只有div 这个祖先节点
    //li[1]/attribute:😗 第一个li 节点的所有属性值
    //li[1]/child::a[@href = “link.html”] 获取 href 属性为link.html 的所有直接a 子节点
    //li[1]/descendant::span 获取所有的子孙节点 所有的span节点
    //li[1]/following:😗[2] 获取当前节点之后的所有节点 这里只获取第二个后续节点
    //li[1]/following - sibling:: * 获取当前结点之后的所有同级节点

使用Beautiful Soup

Beautiful Soup : 借助网页的结构和属性等特性来解析网页

  1. 解析器:

    Beautiful Soup 在解析式 实际上依赖解析器,lxml 解析器有解析 HTML 和 XML 的功能, 而且速度快,容错能力强,所以推荐使用它

  2. 基本用法:

    import requests
    from bs4 import BeautifulSoup
    
    response = requests.get('https://zhidao.baidu.com/question/268587066.html')
    response.encoding = 
  • 56
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值