python爬虫记录

文章目录

# Python爬虫介绍

01. Python虚拟环境搭建

此处推荐使用国内源Anaconda下载安装使用,可以参考下面的文章:

一、安装环境

sudo pip3 install virtualenv -i https://pypi.douban.com/simple/

二、安装virtualenvwrapper

sudo pip3 install virtualenvwrapper -i https://pypi.douban.com/simple/

三、配置

  • sudo vim ~/.bashrc
export WORKON_HOME=/home/ljh/.virtualenvs 
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3.5 
source  /usr/local/bin/virtualenvwrapper.sh
  • source ~/.bashrc

四、创建虚拟环境

mkvirtualenv testlev

五、切换虚拟环境

workon testlev

六、关闭虚拟环境

deactivate testlev

七、删除虚拟环境

rmvirtualenv testlev

02. 爬虫介绍

  • 什么是爬虫?

    网络爬虫(又被称为网页蜘蛛,网络机器人), 是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。

  • 获取数据几种途径

  • 爬虫的作用

    • 数据分析
    • 购物助手
    • 咨询网站
    • 搜索引擎
  • 需要知识

    • Python 基础知识
    • HTML 基础知识
    • 数据持久化知识
    • Scrapy框架知识
  • 爬虫的分类

    • 通用爬虫

      • python爬虫记录
      • 通用网络爬虫 是 捜索引擎抓取系统(Baidu、Google、Yahoo等)的重要组成部分。主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。
    • 聚焦爬虫

      • 聚焦爬虫,是"面向特定主题需求"的一种网络爬虫程序,它与通用搜索引擎爬虫的区别在于:
    • 不同

      • 聚焦爬虫在实施网页抓取时会对内容进行处理筛选,尽量保证只抓取与需求相关的网页信息。
  • Robots协议

    全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取,

    例如:https://www.jd.com/robots.txt

03. HTTP与HTTPS

  • HTTP协议

    • 中文名叫超文本传输协议: 是用于从网络传送超文本数据到本地浏览器的传送协议
  • HTTPS协议

    • 简单讲是HTTP的安全版,在HTTP协议的基础上加入SSL层(HTTP+SSL) 。 SSL(Secure Sockets Layer 安全套接层)主要用于Web的安全传输协议,在传输层对网络连接进行加密,保障在Internet上数据传输的安全。
  • 端口

    • HTTP的端口号为80HTTPS的端口号为443
  • SSL

    • HTTPS的安全基础是SSL,因此通过它可以传输的内容都是经过SSL加密的
      • 建立一个安全有效的信息传送通道,保证数据传送的安全性
      • 确定网站的真实性和有效性
  • 请求与响应

    • 1.域名解析 -->

      2.发起TCP的3次握手 -->

      3.建立TCP连接后发起http请求 -->

      4.服务器响应http请求,浏览器得到html代码 -->

      5.浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) -->

      6.浏览器对页面进行渲染呈现给用户.

    • python爬虫记录

  • URL

    • 统一资源定位符,是用于完整地描述Internet上网页和其他资源的地址的一种标识方法。
    • 组成 https://book.qidian.com/info/1004608738#Catalog
      • scheme:协议
      • host:服务器的IP地址或者域名
      • port:服务器的端口
      • path:访问资源的路径
      • query-string:参数
      • anchor:锚
  • 请求方法

    • python爬虫记录
  • 常用请求头

    • Accept: 指定客户端能够接收的内容类型。

    • Accept-Charset: 浏览器可以接受的字符编码集。

    • Accept-Encoding: 指定浏览器可以支持的web服务器返回内容压缩编码类型。

    • Accept-Language: 浏览器可接受的语言。

    • Accept-Ranges: 可以请求网页实体的一个或者多个子范围字段。

    • AuthorizationHTTP: 授权的授权证书。

    • Cache-Control: 指定请求和响应遵循的缓存机制。

    • Connection: 表示是否需要持久连接。(HTTP 1.1默认进行持久连接)

    • CookieHTTP: 请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。

    • Content-Length: 请求的内容长度。

    • Content-Type: 请求的与实体对应的MIME信息。

    • Date: 请求发送的日期和时间。

    • Expect: 请求的特定的服务器行为。

    • From: 发出请求的用户的Email。

    • Host: 指定请求的服务器的域名和端口号。

    • If-Match: 只有请求内容与实体相匹配才有效。

    • If-Modified-Since: 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码。

    • If-None-Match: 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变。

    • If-Range: 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。

    • If-Unmodified-Since: 只在实体在指定时间之后未被修改才请求成功。

    • Max-Forwards: 限制信息通过代理和网关传送的时间。

    • Pragma: 用来包含实现特定的指令。

    • Proxy-Authorization: 连接到代理的授权证书。

    • Range: 只请求实体的一部分,指定范围。

    • Referer: 先前网页的地址,当前请求网页紧随其后,即来路。

    • TE: 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息。

    • Upgrade: 向服务器指定某种传输协议以便服务器进行转换(如果支持。

    • User-Agent 是否是浏览器。

    • Via: 通知中间网关或代理服务器地址,通信协议。

    • Warning: 关于消息实体的警告信息

  • 响应头

    • Accept-Ranges: 表明服务器是否支持指定范围请求及哪种类型的分段请求。

    • Age: 从原始服务器到代理缓存形成的估算时间(以秒计,非负)。

    • Allow: 对某网络资源的有效的请求行为,不允许则返回405。

    • Cache-Control: 告诉所有的缓存机制是否可以缓存及哪种类型。

    • Content-Encodingweb: 服务器支持的返回内容压缩编码类型。。

    • Content-Language: 响应体的语言。

    • Content-Length: 响应体的长度。

    • Content-Location: 请求资源可替代的备用的另一地址。

    • Content-MD5: 返回资源的MD5校验值。

    • Content-Range: 在整个返回体中本部分的字节位置。

    • Content-Type: 返回内容的MIME类型。

    • Date: 原始服务器消息发出的时间。

    • ETag: 请求变量的实体标签的当前值。

    • Expires: 响应过期的日期和时间。

    • Last-Modified: 请求资源的最后修改时间。

    • Location: 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源。

    • Pragma: 包括实现特定的指令,它可应用到响应链上的任何接收方。

    • Proxy-Authenticate: 它指出认证方案和可应用到代理的该URL上的参数。

    • refresh: 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持)

    • Retry-After: 如果实体暂时不可取,通知客户端在指定时间之后再次尝试。

    • Serverweb: 服务器软件名称。

    • Set-Cookie: 设置Http Cookie。

    • Trailer: 指出头域在分块传输编码的尾部存在。

    • Transfer-Encoding: 文件传输编码。

    • Vary: 告诉下游代理是使用缓存响应还是从原始服务器请求。

    • Via: 告知代理客户端响应是通过哪里发送的。

    • Warning: 警告实体可能存在的问题。

    • WWW-Authenticate: 表明客户端请求实体应该使用的授权方案。

  • 状态码

    • 200 - 请求成功
    • 301 - 资源(网页等)被永久转移到其它URL
    • 302 - 资源(网页等)被临时转移到其它URL
    • 401 - 未授权
    • 403 - 禁止访问
    • 408 - 请求超时
    • 404 - 请求的资源(网页等)不存在
    • 500 - 内部服务器错误
    • 503 - 服务器不可用

# urllib基本使用

04.Urllib的Get和Post用法

  • Decode

    • Decode的作用是将其他编码的字符串转换成unicode编码,如str.decode(‘gb2312’),表示将gb2312编码的字符串str1转换成unicode编码。
  • Encode

    • Encode的作用是将unicode编码转换成其他编码的字符串,如str.encode(‘gb2312’),表示将unicode编码的字符串str2转换成gb2312编码。
  • Get请求

    • URL编码
    word = {"wd" : "美女"}
    # 通过urllib.urlencode()方法,将字典键值对按URL编码转换,从而能被web服务器接受。
    result = urllib.parse.urlencode(word) 
    print(result)
    
    • 解码
    result = urllib.parse.unquote(result)
    print(result)
    
    • 发送请求
     response = urllib.request.urlopen(request)
     print(response.read())
    
    
  • POST请求

    • # POST请求的目标URL(这个代码是之前的链接,方便我们使用,不用传递sign参数,新版中该参数是加密的)
      url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null"
      #构建表单数据
      formdata = {
          'i': '你好',
          'from': 'AUTO',
          'to': 'AUTO',
          'smartresult': 'dict',
          'client': 'fanyideskweb',
          'doctype': 'json',
          'version': '2.1',
          'keyfrom': 'fanyi.web',
          'action': 'FY_BY_CLICKBUTTION',
          'typoResult': 'false',
      }
      
      formdata = urllib.parse.urlencode(formdata)
      formdata = formdata.encode('utf-8')
      
      req = request.Request(url, data = formdata, headers = headers)
      #发起请求获取响应结果
      response = request.urlopen(req)
      #打印获取的响应结果
      print (response.read().decode('utf-8'))
      
  • 忽略SSL验证

    python爬虫记录

    from urllib import request
    # 1. 导入Python SSL处理模块
    import ssl
    # 2. 表示忽略未经核实的SSL证书认证
    context = ssl._create_unverified_context()
    # 目标url
    url = "https://www.12306.cn/mormhweb/"
    #设置请求头
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
    #构建request对象
    request = urllib.request.Request(url, headers = headers)
    # 3. 在urlopen()方法里 指明添加 context 参数
    response = urllib.request.urlopen(request, context = context)
    html = response.read().decode()
    print (html)
    
    

05. Urllib其他用法

  • urlparse()实现URL的识别和分段

    	url = 'https://book.qidian.com/info/1004608738?wd=123&page=20#Catalog'
    """
    url:待解析的url
    scheme='':假如解析的url没有协议,可以设置默认的协议,如果url有协议,设置此参数无效
    allow_fragments=True:是否忽略锚点,默认为True表示不忽略,为False表示忽略
    """
    result = parse.urlparse(url=url,scheme='http',allow_fragments=True)
    print(result)
    print(result.scheme)
    
  • urlunparse()可以实现URL的构造

  • url_parmas = ('https', 'book.qidian.com', '/info/1004608738', '', 'wd=123&page=20', 'Catalog')
    #components:是一个可迭代对象,长度必须为6
    result = parse.urlunparse(url_parmas)
    print(result)
    """
    https://book.qidian.com/info/1004608738?wd=123&page=20#Catalog
    """
    
  • urljoin()传递一个基础链接,根据基础链接可以将某一个不完整的链接拼接为一个完整链接

    base_url = 'https://book.qidian.com/info/1004608738?wd=123&page=20#Catalog'
    sub_url = '/info/100861102'
    full_url = parse.urljoin(base_url,sub_url)
    print(full_url)
    
    
  • parse_qs()将url编码格式的参数反序列化为字典类型

  • parmas_str = 'page=20&wd=123'
    parmas = parse.parse_qs(parmas_str)
    print(parmas)
    """
    {'page': ['20'], 'wd': ['123']}
    """
    
  • quote()可以将中文转换为URL编码格式

  • word = '中国梦'
    url = 'http://www.baidu.com/s?wd='+parse.quote(word)
    print(parse.quote(word))
    print(url)
    """
    %E4%B8%AD%E5%9B%BD%E6%A2%A6
    http://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD%E6%A2%A6
    """
    
  • unquote:可以将URL编码进行解码

  • url = 'http://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD%E6%A2%A6'
    print(parse.unquote(url))
    """
    http://www.baidu.com/s?wd=中国梦
    """
    

06. Urllib异常错误

  • URLError

    • 来自urllib库的error模块,继承自OSError,由request模块产生的异常都可以通过捕捉这个类来处理.
      • 没有网络连接
      • 服务器连接失败
      • 找不到指定的服务器
  • HTTPError

    • HTTPError是URLError的子类,我们发出一个请求时,服务器上都会对应一个response应答对象,其中它包含一个数字"响应状态码"。

    • 专门用来处理HTTP请求错误,比如未认证,页面不存在等

    • 有三个属性:

      • code:返回HTTP的状态码

      • reason:返回错误原因

      • headers:返回请求头

      from urllib import request,error
      def check_error():
          """
          因为HTTPError的父类是URLError,所以我们更好的处理顺序应该是
          先捕获子类的错误,再捕获父类的错误
          """
          req_url = 'https://www.baiduxxx.com/'
          try:
              response = request.urlopen(url=req_url)
              print(response.status)
          except error.HTTPError as err:
              print(err.code,err.reason,err.headers)
          except error.URLError as err:
              print('===', err.reason)
      
      

07. Urllib代理设置

  • 自定义Opener

我们之前一直都在使用的urlopen,它是一个特殊的opener,是模块帮我们创建好的。自定义Opener会有更高级的用法

import urllib.request
# 构建一个HTTPHandler 处理器对象,支持处理HTTP请求
http_handler = urllib.request.HTTPHandler()
# 构建一个HTTPHandler 处理器对象,支持处理HTTPS请求
# http_handler = urllib.request.HTTPSHandler()
# 调用urllib.request.build_opener()方法,创建支持处理HTTP请求的opener对象
opener = urllib.request.build_opener(http_handler)
# 构建 Request请求
request = urllib.request.Request("http://www.baidu.com/")
# 调用自定义opener对象的open()方法,发送request请求
response = opener.open(request)
# 获取服务器响应内容
print (response.read().decode())

  • 代理设置

    • python爬虫记录

    • 代理的作用:

      • 1.突破自身IP访问限制,访问一些平时不能访问的站点。

      • 2.访问一些单位或团体内部资源:比如使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。

      • 3.提高访问速度:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,以提高访问速度。

      • 4.隐藏真实IP:上网者也可以通过这种方法隐藏自己的IP,免受攻击。对于爬虫来说,我们用代理就是为了隐藏自身IP,防止自身的IP被*。

    • 根据协议划分

      • FTP代理服务器**:主要用于访问FTP服务器,一般有上传、下载的功能以及缓存的功能,端口号一般为21,2121等。**

      • HTTP代理服务器**:主要用于访问网页,一般有内容过滤和缓存的功能,端口号一般为80、8080、3128等**

      • SSL/TLS代理:主要能用于访问加密的网站,一般有SSL或者TLS加密**

      • SOCKS代理:只是单纯的用于传输数据包,不关心具体的协议用法,速度快、有缓存功能,端口号一般为1080

    • 根据匿名内容划分

      • 高度匿名代理:会将数据包原封不动的转发,在服务器看来就好像真的是一个普通的用户短在访问,而记录的IP就是代理服务器的IP

      • 普通匿名代理:会在数据包上做一些改动,服务端上有可能发现这个是代理服务器,也有一定的几率追查到客户端的真实IP.

      • 透明代理:不但改动了数据包,还会告诉服务器客户端的真实IP,这种代理除了用缓存技术提高浏览器速度。能用内容过滤提高安全性之外,并没有其他作用。

      • 使用代理IP这是爬虫/反爬虫的第二大招,通常也是最好用的。

  • 代理网站

    • 西刺免费代理IP
    • 快代理免费代理
from urllib import request,error
#构建支持代理的handler
proxy = {
    'http':'61.138.33.20:808',
    'https':'120.69.82.110:44693',
}
proxy_handler = request.ProxyHandler(
    proxies=proxy
)
# 构建一个私密代理Handler,需要加上私密代理账户的用户名和密码
# authproxy = {
#    "http" :"username:password@61.135.217.7:80"
#}
# authproxy_handler=urllib.request.ProxyHandler(
#    proxies=authproxy
#)
#根据proxy_handler实例化一个opener对象
opener = request.build_opener(proxy_handler)
url = 'http://www.baidu.com/'
# 使用https://httpbin.org/get接口验证使用了代理
# url = 'https://httpbin.org/get'
try:
    response = opener.open(url,timeout=5)
    print(response.status)
except error.HTTPError as err:
    print(err.reason)
except error.URLError as err:
    print(err.reason)
# 1. 如果按照上面代码,只有使用opener.open()方法发送
请求才使用自定义的代理,而urlopen()则不使用自定义代理。
response = opener.open(request)
# 2. 将自定义的opener设置为全局的opener,之后所有的,不管是
opener.open()还是urlopen() 发送请求,都将使用自定义代理。
# request.install_opener(opener)
# response = urlopen(request)

08. Cookie的作用

  • Cookies的作用

    • Cookies是最直接的应用就是检测用户是否已经登录
    获取到一个有登录信息的Cookie模拟登陆
    # -*- coding:utf-8 -*-
    import urllib.request
    url = 'https://www.douban.com/people/175417123/'
    #根据刚才的登录信息来构建一个已经登录过的用户的headers信息
    headers = {
        'User-Agent':' Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0',
        'Host':'www.renren.com',
        'Cookie':'anonymid=jgoj4xlw-3izsk4; depovince=BJ; jebecookies=62d94404-de1f-450a-919b-a2d9f4c8b811|||||; _r01_=1; JSESSIONID=abchsGLNgne0L8_wz2Emw; ick_login=cf54f2dc-8b0b-417a-96b2-32d4051f7236; jebe_key=02cb19ad-2966-4641-8828-217160ca67a0%7Cba6f6d6ec917200a4e17a85dbfe33a4a%7C1525230975024%7C1%7C1525230982574; t=87a502d75601f8e8c0c6e0f79c7c07c14; societyguester=87a502d75601f8e8c0c6e0f79c7c07c14; id=965706174; xnsid=e1264d85; ver=7.0; loginfrom=null; wp_fold=0',
    }
    # 2. 通过headers里的报头信息(主要是Cookie信息),构建Request对象
    request = urllib.request.Request(url, headers=headers)
    # 3. 直接豆瓣个人主页(主要是Cookie信息)
    #,判断这是一个已经登录的用户,并返回相应的页面
    response = urllib.request.urlopen(request)
    # 4. 打印响应内容
    print (response.read().decode())
    
    
  • CookieJar

    • 用来储存Cookie值,存在内存中,向传出的HTTP请求添加cookie的对象。
    import http.cookiejar as cookiejar
    from urllib import parse,request
    #1.构造一个CookieJar对象实例来保存cookie
    cookie = cookiejar.CookieJar()
    # 2.使用HTTPCookieProcessor()创建cookie处理器对象,
    # 参数为CookieJar()对象
    cookie_handler = request.HTTPCookieProcessor(cookie)
    #3.通过build_opener()来构建opener
    opener = request.build_opener(cookie_handler)
    #4.addheaders接受一个列表,里面每一个元素都是一个headers信息的元组
    #opener将会附带header信息
    opener.addheaders = [
        ('User-Agent','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0'),
    ]
    #5.需要登录账号和密码
    data = {
        'source': 'index_nav',
        'form_email': '18518753265',
        'form_password': 'ljh123456',
    }
    #6. 通过urlencode()转码
    postdata = parse.urlencode(data).encode('utf-8')
    #7. 构建Request请求对象,包含需要发送的用户名和密码
    request = request.Request("https://www.douban.com/accounts/login", data = postdata)
    # 8. 通过opener发送这个请求,并获取登录后的Cookie值,
    opener.open(request)
    # 9. opener包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面
    response = opener.open("https://www.douban.com/people/175417123/")
    #这里为了测试不添加cookie时访问改界面的效果
    #headers = {
    #    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 #Firefox/59.0',
    #}
    # request = request.Request('https://www.douban.com/people/175417123/',headers=headers)
    # response = request.urlopen(request)
    # 10. 打印响应内容
    #打印结果查看是否访问成功
    print(response.code)
    html = response.read().decode('utf-8')
    # print(html)
    with open('douban_login.html','w') as f:
        f.write(html)
    
    

# Request使用

09. Requests的Get和Post用法

  • requests

    • requests是python实现的简单易用的HTTP库,使用起来比urllib简洁很多。
  • Get请求

    response = requests.get("http://www.baidu.com/")
    * response的常用方法:
        * response.text  返回解码后的字符串
        * respones.content  以字节形式(二进制)返回。
        * response.status_code  响应状态码
        * response.request.headers  请求的请求头
        * response.headers  响应头
        * response.encoding = 'utf-8'   可以设置编码类型
        * response.encoding       获取当前的编码
        * response.json()   内置的JSON解码器,以json形式返回,前提返回的内容确保是json格式的,不然解析出错会抛异常
    
    
  • 添加请求头

    import requests
    kw = {'wd':'美女'}
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
    }
    # params 接收一个字典或者字符串的查询参数,
    # 字典类型自动转换为url编码,不需要urlencode()
    response = requests.get(
        "http://www.baidu.com/s?",
        params = kw, 
        headers = headers
    )
    
  • 注意

    • 使用response.text 时,Requests 会基于 HTTP 响应的文本编码自动解码响应内容,大多数 Unicode 字符集都能被无缝地解码,但是也会出现乱码请求。推荐使用response.content.deocde()
    • 使用response.content 时,返回的是服务器响应数据的原始二进制字节流,可以用来保存图片等二进制文件。
  • Post请求

    import requests
    req_url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null"
    #分析表单数据
    formdata = {
        'i': '老鼠爱大米',
        'from': 'AUTO',
        'to': 'AUTO',
        'smartresult': 'dict',
        'client': 'fanyideskweb',
        'doctype': 'json',
        'version': '2.1',
        'keyfrom': 'fanyi.web',
        'action': 'FY_BY_CLICKBUTTION',
        'typoResult': 'false',
    }
    #添加请求头
    req_header = {
        'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
    }
    response = requests.post(
        req_url, 
        data = formdata, 
        headers = req_header
    )
    #print (response.text)
    # 如果是json文件可以直接显示
    print (response.json())
    
    

10. Requests的其他用法

  • 上传文件

    url = 'https://httpbin.org/post'
    files = {'file': open('image.png', 'rb')}
    response = requests.post(url, files=files)
    print(response.text)
    
  • Web客户端验证

    import requests
    auth=('test', '123456')
    response = requests.get(
        'http://192.168.199.107', 
        auth = auth
    )
    print (response.text)
    
  • 代理设置

    import requests
    # 根据协议类型,选择不同的代理
    proxies = {
        "http": "http://11.44.156.126:4532",
        "https": "http://11.134.156.126:4532",
    }
    ##如果代理需要使用HTTP Basic Auth,可以使用下面这种格式:
    '''
    proxy = { 
        "http": "name:password@11.134.156.126:4532" 
    }
    '''
    
    response = requests.get(
        "http://www.baidu.com", 
        proxies = proxies
    )
    print(response.text)
    
  • Cookies

    import requests
    response = requests.get("https://www.douban.com/")
    # 7\. 返回CookieJar对象:
    cookiejar = response.cookies
    # 8\. 将CookieJar转为字典:
    cookiedict = requests.utils.dict_from_cookiejar(
        cookiejar
    )
    print (cookiejar)
    print (cookiedict)
    
  • Session

    import requests
    # 1\. 创建session对象,可以保存Cookie值
    ssion = requests.session()
    # 2\. 处理 headers
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
    }
    # 3\. 需要登录的用户名和密码
    data = {
        "email":"18518753265",
        "password":"ljh123456"
    }
    # 4\. 发送附带用户名和密码的请求,并获取登录后的Cookie值,保存在ssion里
    ssion.post(
        "http://www.renren.com/PLogin.do",
        data = data
    )
    # 5\. ssion包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面
    response = ssion.get(
        "http://www.renren.com/965722397/profile"
    )
    # 6\. 打印响应内容
    print (response.text)
    
  • 跳过SSL验证

    import requests
    response = requests.get("https://www.12306.cn/mormhweb/", verify = False)
    print (response.text)
    

# 正则

11. 正则

  • 正则

    • 正则表达式是一种特殊的字符串模式,用于匹配一组字符串
  • 在线网站

  • 为什么要学正则

    • 用正则提取我们想要的数据
  • compile 函数

    • 用于编译正则表达式,生成一个 Pattern 对象
      • re.I 使用匹配对大小写不敏感(不区分大小写)
      • re.S 使.匹配包括换行符在内的所有字符
      • re.M 多行匹配
      • re.L 做本地化识别
  • match 方法

    • 从起始位置开始查找,一次匹配

      import re
      
      pattern = re.compile('\d', re.S)
      result = re.match(pattern, '12')
      print(result.group())
      
      
  • search 方法

    • 从任何位置开始查找,一次匹配

      import re
      
      pattern = re.compile('\d', re.S)
      result = re.search(pattern, 'a12')
      print(result.group())
      
  • findall 方法

    • 全部匹配,返回列表

      import re
      
      pattern = re.compile('\d', re.S)
      result = re.findall(pattern, 'a12')
      print(result)
      
  • split 方法

    • 分割字符串,返回列表

      import re
      
      pattern = re.compile('\d', re.S)
      result = re.split(pattern, 'a1b2c')
      print(result)
      
  • sub 方法

    • 替换

      import re
      
      pattern = re.compile('\d', re.S)
      result = re.sub(pattern, 'a', '1234')
      print(result)
      
      

13. Xpath表达式

  • 什么是xpath?
    XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。
  • 什么是xml?W3School
    • XML 指可扩展标记语言(EXtensible Markup Language)
    • XML 是一种标记语言,很类似 HTML
    • XML 的设计宗旨是传输数据,而非显示数据
    • XML 标签没有被预定义。您需要自行定义标签。
    • XML 被设计为具有自我描述性。
    • XML 是 W3C 的推荐标准
  • XML和 HTML 的区别
数据格式 描述 作用
XML 可扩展标记语言 用来传输和存储数据
HTML 超文本标记语言 用来显示数据
  • 常见语法
表达式 含义
/ 从根节点开始
// 从任意节点
. 从当前节点
从当前节点的父节点
@ 选取属性
text() 选取文本
  • 常用用法
from lxml import etree
data = """
        <div>
            <ul>
                 <li class="item-0"><a href="link1.html">first item</a></li>
                 <li class="item-1"><a href="link2.html">second item</a></li>
                 <li class="item-inactive"><a href="link3.html">third item</a></li>
                 <li class="item-1" id="1" ><a href="link4.html">fourth item</a></li>
                 <li class="item-0" data="2"><a href="link5.html">fifth item</a>
             </ul>
         </div>
        """

html = etree.HTML(data)#构造了一个XPath解析对象。etree.HTML模块可以自动修正HTML文本。

li_list = html.xpath('//ul/li')#选取ul下面的所有li节点
#li_list = html.xpath('//div/ul/li')#选取ul下面的所有li节点

a_list = html.xpath('//ul/li/a')#选取ul下面的所有a节点
herf_list = html.xpath('//ul/li/a/@href')#选取ul下面的所有a节点的属性herf的值
text_list = html.xpath('//ul/li/a/text()')#选取ul下面的所有a节点的值
print(li_list)
print(a_list)
print(herf_list)
print(text_list)

#打印
[<Element li at 0x1015f4c48>, <Element li at 0x1015f4c08>, <Element li at 0x1015f4d08>, <Element li at 0x1015f4d48>, <Element li at 0x1015f4d88>]
[<Element a at 0x1015f4dc8>, <Element a at 0x1015f4e08>, <Element a at 0x1015f4e48>, <Element a at 0x1015f4e88>, <Element a at 0x1015f4ec8>]
['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
['first item', 'second item', 'third item', 'fourth item', 'fifth item']
  • 通配符
通配符 含义
* 选取任何元素节点
@* 选取任何属性的节点
  • 常见用法
from lxml import etree
data = """
        <div>
            <ul>
                 <li class="item-0"><a href="link1.html">first item</a></li>
                 <li class="item-1"><a href="link2.html">second item</a></li>
                 <li class="item-inactive"><a href="link3.html">third item</a></li>
                 <li class="item-1" id="1" ><a href="link4.html">fourth item</a></li>
                 <li class="item-0" data="2"><a href="link5.html">fifth item</a>
             </ul>
         </div>
        """

html = etree.HTML(data)

li_list = html.xpath('//li[@class="item-0"]')#选取class为item-0的li标签
text_list = html.xpath('//li[@class="item-0"]/a/text()')#选取class为item-0的li标签 下面a标签的值
li1_list  = html.xpath('//li[@id="1"]')#选取id属性为1的li标签
li2_list  = html.xpath('//li[@data="2"]')#选取data属性为2的li标签
print(li_list)
print(text_list)
print(li1_list)
print(li2_list)

#打印
[<Element li at 0x101dd4cc8>, <Element li at 0x101dd4c88>]
['first item', 'fifth item']
[<Element li at 0x101dd4d88>]
[<Element li at 0x101dd4c88>]

  • 表达式
表达式 含义
[?] 选取第几个节点
last() 选取最后一个节点
last()-1 选取倒数第二个节点
position()-1 选取前两个
  • 常见用法
from lxml import etree

data = jiayuan

html = etree.HTML(data)

li_list = html.xpath('//ul/li[1]')  # 选取ul下面的第一个li节点
li1_list = html.xpath('//ul/li[last()]')  # 选取ul下面的最后一个li节点
li2_list = html.xpath('//ul/li[last()-1]')  # 选取ul下面的最后一个li节点
li3_list = html.xpath('//ul/li[position()<= 3]')  # 选取ul下面前3个标签
text_list = html.xpath('//ul/li[position()<= 3]/a/@href')  # 选取ul下面前3个标签的里面的a标签里面的href的值
print(li_list)
print(li1_list)
print(li2_list)
print(li3_list)
print(text_list)

#打印
[<Element li at 0x1015d3cc8>]
[<Element li at 0x1015d3c88>]
[<Element li at 0x1015d3d88>]
[<Element li at 0x1015d3cc8>, <Element li at 0x1015d3dc8>, <Element li at 0x1015d3e08>]
['link1.html', 'link2.html', 'link3.html']

  • 函数
函数名 含义
starts-with 选取以什么开头的元素
contains 选取包含一些信息的元素
and 并且的关系
or 或者的关系
from lxml import etree

data = """
        <div>
            <ul>
                 <li class="item-0"><a href="link1.html">first item</a></li>
                 <li class="item-1"><a href="link2.html">second item</a></li>
                 <li class="item-inactive"><a href="link3.html">third item</a></li>
                 <li class="item-1" id="1" ><a href="link4.html">fourth item</a></li>
                 <li class="item-0" data="2"><a href="link5.html">fifth item</a>
             </ul>
         </div>
        """

html = etree.HTML(data)

li_list = html.xpath('//li[starts-with(@class,"item-1")]')#获取class包含以item-1开头的li标签
li1_list = html.xpath('//li[contains(@class,"item-1")]')#获取class包含item的li标签
li2_list = html.xpath('//li[contains(@class,"item-0") and contains(@data,"2")]')#获取class为item-0并且data为2的li标签
li3_list = html.xpath('//li[contains(@class,"item-1") or contains(@data,"2")]')#获取class为item-1或者data为2的li标签
print(li_list)
print(li1_list)
print(li2_list)
print(li3_list)

#打印
[<Element li at 0x101dcac08>, <Element li at 0x101dcabc8>]
[<Element li at 0x101dcac08>, <Element li at 0x101dcabc8>]
[<Element li at 0x101dcacc8>]
[<Element li at 0x101dcac08>, <Element li at 0x101dcabc8>, <Element li at 0x101dcacc8>]
  • 插件
    • Chrome插件 XPath Helper
    • Firefox插件 XPath Checker

练习

爬取斗图啦:https://www.pkdoutu.com/article/list/?page=1

import requests
from lxml import etree
import os

'''
# 爬取的网站:url
https://www.pkdoutu.com/article/list/?page=2

# 解析到图片的思路
//div[@class="col-sm-9 center-wrap"]//a
//div[@class="col-sm-9 center-wrap"]//a/div[@class="random_title"]/text()
//div[@class="col-sm-9 center-wrap"]//a/div[@class="random_article"]//img/@data-original
'''


class DouTuLaSpider():
    def __init__(self):
        self.url = 'https://www.pkdoutu.com/article/list/?page='
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36'
        }

    # 发送请求
    def send_request(self, url):
        print(url)
        response = requests.get(url=url, headers=self.headers)
        return response

    def parse_content(self, response):
        html = response.text
        content = etree.HTML(html)
        a_list = content.xpath('//div[@class="col-sm-9 center-wrap"]//a')
        print(a_list)
        for a in a_list:
            title = a.xpath('./div[@class="random_title"]/text()')  # xpath取出来的是列表
            pic_list = a.xpath('./div[@class="random_article"]//img/@data-original')
            if title:
                if not os.path.exists('doutu/' + title[0]):
                    os.mkdir('doutu/' + title[0])
                for index, pic in enumerate(pic_list):
                    response = self.send_request(pic)  # 发送图片请求
                    name = str(index + 1) + "_" + pic[-20:]  # 图片名字
                    self.write_content(response, name, 'doutu/' + title[0])

    def write_content(self, response, name, path):
        print('正在写入%s' % name)
        with open(path + '/' + name, 'wb') as f:
            f.write(response.content)

    def start(self):
        for i in range(10, 20):
            full_url = self.url + str(i)
            reponse = self.send_request(full_url)
            self.parse_content(reponse)


if __name__ == '__main__':
    dtl = DouTuLaSpider()
    dtl.start()

爬取链家:https://sh.lianjia.com/chengjiao/pg1/

# bs4使用

15. bs4

  • BS4
    • Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.
  • 安装
    • pip install beautifulsoup4
  • 解析器
表达式 使用方法 优势
Python标准库 BeautifulSoup(markup, “html.parser”) Python的内置标准库
执行速度适中
文档容错能力强
lxml HTML 解析器 BeautifulSoup(markup, “lxml”) 速度快
文档容错能力强
lxml XML 解析器 BeautifulSoup(markup, [“lxml-xml”]) BeautifulSoup(markup, “xml”) 速度快
唯一支持XML的解析器
html5lib BeautifulSoup(markup, “html5lib”) 最好的容错性
以浏览器的方式解析文档
生成HTML5格式的文档
  • 对象种类

    • Tag

      soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
      tag = soup.b
      type(tag)
      # <class 'bs4.element.Tag'>
      
    • Name

      tag.name
      # 'b'
      
    • attrs

      tag.attrs
      # {u'class': u'boldest'}
      
    • NavigableString

      tag.string
      #Extremely bold
      
    • 搜索文档树

      html_doc = """
      <html><head><title>The Dormouse's story</title></head>
      <body>
      <p class="title"><b>The Dormouse's story</b></p>
      
      <p class="story">Once upon a time there were three little sisters; and their names were
      <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
      <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
      <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
      and they lived at the bottom of a well.</p>
      
      <p class="story">...</p>
      """
      
      from bs4 import BeautifulSoup
      soup = BeautifulSoup(html_doc, 'html.parser')
      
      • find_all(name, attrs, recursive, text, **kwargs)

        • 字符串

          soup.find_all('b')
          # [<b>The Dormouse's story</b>]
          
        • 正则

          import re
          for tag in soup.find_all(re.compile("^b")):
              print(tag.name)
          # body
          # b
          
        • 列表

          soup.find_all(["a", "b"])
          # [<b>The Dormouse's story</b>,
          #  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
          #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
          #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
          
        • 关键字

          soup.find_all(id='link2')
          # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
          soup.find_all(href=re.compile("elsie"))
          # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
          
        • 按CSS搜索

          soup.find_all("a", class_="sister")
          # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
          #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
          #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
          
  • CSS选择器

    soup.select("title")
    # [<title>The Dormouse's story</title>]
    
    soup.select("p nth-of-type(3)")
    # [<p class="story">...</p>]
    
    • 通过tag标签逐层查找

      soup.select("body a")
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      #  <a class="sister" href="http://example.com/lacie"  id="link2">Lacie</a>,
      #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      
      soup.select("html head title")
      # [<title>The Dormouse's story</title>]
      
    • 找到某个tag标签下的直接子标签

      soup.select("head > title")
      # [<title>The Dormouse's story</title>]
      
      soup.select("p > a")
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      #  <a class="sister" href="http://example.com/lacie"  id="link2">Lacie</a>,
      #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      
      soup.select("p > a:nth-of-type(2)")
      # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
      
      soup.select("p > #link1")
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
      
      soup.select("body > a")
      # []
      
    • 找到兄弟节点标签:

      soup.select("#link1 ~ .sister")
      # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
      #  <a class="sister" href="http://example.com/tillie"  id="link3">Tillie</a>]
      
      soup.select("#link1 + .sister")
      # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
      
    • 通过CSS的类名查找

      soup.select(".sister")
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
      #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      
      soup.select("[class~=sister]")
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
      #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      
    • 通过tag的id查找:

      soup.select("#link1")
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
      
      soup.select("a#link2")
      # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
      
    • 同时用多种CSS选择器查询元素:

      soup.select("#link1,#link2")
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
      
    • 通过是否存在某个属性来查找:

      soup.select('a[href]')
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
      #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      
    • 通过属性的值来查找:

      soup.select('a[href="http://example.com/elsie"]')
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
      
      soup.select('a[href^="http://example.com/"]')
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
      #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      
      soup.select('a[href$="tillie"]')
      # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
      
      soup.select('a[href*=".com/el"]')
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
      

    • 返回查找到的元素的第一个

      soup.select_one(".sister")
      # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
      

16.bs4案例

使用流程:
- 导包:from bs4 import BeautifulSoup
- 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容
(1)转化本地文件:
- soup = BeautifulSoup(open(‘本地文件’), ‘lxml’)
(2)转化网络文件:
- soup = BeautifulSoup(‘字符串类型或者字节类型’, ‘lxml’)
(3)打印soup对象显示内容为html文件中的内容

基础巩固:
(1)根据标签名查找
- soup.a 只能找到第一个符合要求的标签
(2)获取属性
- soup.a.attrs 获取a所有的属性和属性值,返回一个字典
- soup.a.attrs[‘href’] 获取href属性
- soup.a[‘href’] 也可简写为这种形式
(3)获取内容
- soup.a.string
- soup.a.text
- soup.a.get_text()
【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
(4)find:找到第一个符合要求的标签
- soup.find(‘a’) 找到第一个符合要求的
- soup.find(‘a’, title=“xxx”)
- soup.find(‘a’, alt=“xxx”)
- soup.find(‘a’, class_=“xxx”)
- soup.find(‘a’, id=“xxx”)
(5)find_all:找到所有符合要求的标签
- soup.find_all(‘a’)
- soup.find_all([‘a’,‘b’]) 找到所有的a和b标签
- soup.find_all(‘a’, limit=2) 限制前两个
(6)根据选择器选择指定的内容
select:soup.select(’#feng’)
- 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
- 层级选择器:
div .dudu #lala .meme .xixi 下面好多级
div > p > a > .lala 只能是下面一级
【注意】select选择器返回永远是列表,需要通过下标提取指定的对象

17.jsonpath

  • jsonpath

    用来解析多层嵌套的json数据;JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Python, PHP 和 Java

  • 文档与安装

    • http://goessner.net/articles/JsonPath
    • pip install jsonpath
  • 用法

    import requests
    import jsonpath
    import json
    import chardet
    url = 'http://www.lagou.com/lbs/getAllCitySearchLabels.json'
    response = requests.get(url)
    html = response.text
    # 把json格式字符串转换成python对象
    jsonobj = json.loads(html)
    # 从根节点开始,匹配name节点
    citylist = jsonpath.jsonpath(jsonobj,'$..name')
    

18. 多线程爬虫

  • 多线程回顾

    • 一个cpu一次只能执行一个任务,多个cpu同时可以执行多个任务
    • 一个cpu一次只能执行一个进程,其它进程处于非运行状态
    • 进程里包含的执行单元叫线程,一个进程可以包含多个线程
    • 一个进程的内存空间是共享的,每个进程里的线程都可以使用这个共享空间
    • 一个线程在使用这个共享空间的时候,其它的线程必须等待(阻塞状态)
    • 互斥锁作用就是防止多个线程同时使用这块内存空间,先使用的线程会将空间上锁,其它的线程处于等待状态。等锁开了才能进
    • 进程:表示程序的一次执行
    • 线程:CPU运算的基本调度单位
    • GIL(全局锁):python里的执行通行证,而且只有一个。拿到通行证的线程就可以进入CPU执行任务。没有GIL的线程就不能执行任务
    • python的多线程适用于大量密集的I/O处理
    • python的多进程适用于大量的密集并行计算
    • 协程切换任务资源很小,效率高
  • 队列

    • 队列(queue)是一种具有先进先出特征的线性数据结构,元素的增加只能在一端进行,元素的删除只能在另一端进行。能够增加元素的队列一端称为队尾,可以删除元素的队列一端则称为队首
    • 栈(stacks)是一种只能通过访问其一端来实现数据存储与检索的线性数据结构,具有后进先出(last in first out,LIFO)的特征

    • 线程池爬虫

    from concurrent.futures import ThreadPoolExecutor
    from concurrent.futures import as_completed
    import requests
    
    url = 'https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3&pn='
    
    
    # 发起请求
    def request(url):  # 可以用不定长参数
        print(url)
        response = requests.get(url)
        return response
    
    
    def parse(result):
        '''
        解析
        :param result:
        :return:
        '''
        return ['https://www.baidu.com/']  # 返回新的url
    
    
    def main():
        with ThreadPoolExecutor(max_workers=28) as executor:
            url_list = []  # 装URL的列表
            for i in range(1, 11):  # 一共发起10也
                full_url = url + str((i - 1) * 10)
                url_list.append(full_url)
            result = executor.map(request, url_list)
            for res in result:
                new_url = parse(res)  # 去解析
                result1 = executor.map(request, new_url)  # 继续请求
                for res1 in result1:
                    print(res1)
    
        # 第二种
        '''
        
        with ThreadPoolExecutor(max_workers=28) as executor:
          future_list = []
          for i in range(1, 11):  # 一共发起10也
                full_url = url + str((i - 1) * 10)
                future= executor.submit(request, full_url)
                future_list.append(future)
        for res in as_completed(futrue_list): 
            print(res.result())              
        '''
    
    
    if __name__ == '__main__':
        main()
    
    
  • 进程池爬虫

    from concurrent.futures import ProcessPoolExecutor
    from concurrent.futures import as_completed
    import requests
    
    url = 'https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3&pn='
    
    
    # 发起请求
    def request(url):  # 可以用不定长参数
        print(url)
        response = requests.get(url)
        return response
    
    
    def parse(result):
        '''
        解析
        :param result:
        :return:
        '''
        return ['https://www.baidu.com/']  # 返回新的url
    
    
    def main():
        with ProcessPoolExecutor(max_workers=3) as executor:
            url_list = []  # 装URL的列表
            for i in range(1, 11):  # 一共发起10也
                full_url = url + str((i - 1) * 10)
                url_list.append(full_url)
            result = executor.map(request, url_list)
            for res in result:
                print(res)
                new_url = parse(res)  # 去解析
                result1 = executor.map(request, new_url)  # 继续请求
                for res1 in result1:
                    print(res1)
        '''第二种
        with ProcessPoolExecutor(max_workers=3) as executor:
            future_list = []
            for i in range(1, 11):  # 一共发起10也
                full_url = url + str((i - 1) * 10)
                future = executor.submit(request, full_url)
                future_list.append(future)
            for res in as_completed(future_list):
                print(res.result())
        '''
    
    
    if __name__ == '__main__':
        main()
    
    
  • 多协程爬虫

    import requests
    import gevent
    from gevent import monkey
    from gevent.pool import Pool
    
    #把当前的IO操作,打上标记,以便于gevent能检测出来实现异步(否则还是串行)
    monkey.patch_all()
    
    
    def task(url):
        '''
        1、request发起请求
        :param url:
        :return:
        '''
        response = requests.get(url)
        print(response.status_code)
        
        
    #控制最多一次向远程提交多少个请求,None代表不限制
    pool = Pool(5)
    gevent.joinall([
        pool.spawn(task,url='https://www.baidu.com'),
        pool.spawn(task,url='http://www.sina.com.cn'),
        pool.spawn(task,url='https://news.baidu.com'),
    ])
    
    gevent+reqeust+Pool(控制每次请求数量)
    

20.selenium

一、Selenium

Selenium是一款自动化测试工具,支持Chrome,Safari,Firefox 等主流界面式浏览器;支持多种语言开发,比如Java,C,Python等

二、文档地址

  • https://selenium-python-zh.readthedocs.io/en/latest/

三、安装

pip install selenium

四、驱动下载

http://npm.taobao.org/mirrors/chromedriver

五、使用

#导入 webdriver
from selenium import webdriver
    
# 要想调用键盘按键操作需要引入keys包
from selenium.webdriver.common.keys import Keys
import time
#*面浏览器相关设置
# 创建chrome参数对象
opt = webdriver.ChromeOptions()
#把chrome设置成为*面模式
opt.set_headless()
#创建chrome*面对象
driver = webdriver.Chrome(
    options=opt, executable_path='/Users/ljh/Desktop/chromedriver'
)
#创建chrome有界面对象
#调用Chrome浏览器创建浏览器对像(指定一下位置)
driver = webdriver.Chrome(
    executable_path='/Users/ljh/Desktop/chromedriver'
)
#打开浏览器,模拟浏览器请求页面
driver.get('http://www.baidu.com/')
#获取页面的信息
html = driver.page_source
print(html)
# 获取页面名为 wrapper的id标签的文本内容
data = driver.find_element_by_id("wrapper").text
#获取标签的属性
attrvaule = driver.find_element_by_id("wrapper").get_attribute('class')
#打印数据内容
print(data)
#打印标题数据
print(driver.title)
#向百度的搜索框输入搜索关键字
driver.find_element_by_id('kw').send_keys('美女')
#百度搜索按钮,click() 是模拟点击
driver.find_element_by_id('su').click()
#获取当前页面的cookies()
cookies = driver.get_cookies()
cookie = ''
for item in cookies:
    cookie += item['name']+item['value']+' ;'
    print(cookie[:-1])
#全选输入框中的内容ctrl+a 
print(driver.find_element_by_id('kw').send_keys(Keys.CONTROL, 'a'))
# ctrl+x 剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL, 'x')
#清空输入框内容
driver.find_element_by_id('kw').clear()
#输入框重新输入内容
driver.find_element_by_id('kw').send_keys('风景')
#模拟回车键
driver.find_element_by_id('su').send_keys(Keys.RETURN)
#获取当前的url
currentUrl = driver.current_url
print(currentUrl)
#截取网页页面(生成当前的页面快照并保存)
driver.save_screenshot('baidu.png')
#睡眠7秒
time.sleep(7)
# 关闭浏览器
driver.quit()
# 关闭当前页面,如果只有一个页面,会关闭浏览器
driver.close()


六、设置代理

opt = webdriver.ChromeOptions()
opt.add_argument("--proxy-server=http://118.20.16.82:9999")

七、添加Cookie

self.browser.add_cookie({
        'domain': '.xxxx.com',  
        'name': cookie['name'],
        'value': cookie['value'],
        'path': '/',#哪个页面添加Cookie
        'expires': None
    })

八、显示等待

显式等待是你在代码中定义等待一定条件发生后再进一步执行你的代码。 最糟糕的案例是使用time.sleep(),它将条件设置为等待一个确切的时间段。 这里有一些方便的方法让你只等待需要的时间。WebDriverWait结合ExpectedCondition 是实现的一种方式。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

九、隐式等待

如果某些元素不是立即可用的,隐式等待是告诉WebDriver去等待一定的时间后去查找元素。 默认等待时间是0秒,一旦设置该值,隐式等待是设置该WebDriver的实例的生命周期。

from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

十、执行JS

driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')

十一、设置无页面

options = webdriver.ChromeOptions()
# 添加*面参数
options.add_argument('--headless')
browser = webdriver.Chrome(options=options)

十二、切换页面

# 获取当前所有句柄(窗口)
all_handles = browser.window_handles
# 切换browser到新的窗口,获取新窗口的对象
browser.switch_to.window(all_handles[1])

21.Scrapy

一、什么是Scrapy

  • Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛
  • Scrapy 使用了 Twisted异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求

二、Scrapy架构图

  • python爬虫记录
  • python爬虫记录

三、安装

pip3 install Scrapy

四、检验

  • python爬虫记录

后记

  • 回头有空准备爬取网页内容并转为Markdown文件
上一篇:冬季实战训练营


下一篇:linux安装python