爬虫02-python爬虫使用的库及详解

1 Urllib库的基本使用

urllib是python内置的HTTP请求库,不需要额外安装模块。
有了它我们只需要关系请求的链接是什么,参数是什么或者请求头的设置是什么,而不用深入了解它内部的底层工作原理。

包含四个模块:

  • urllib.request: 请求模块
  • urllib.error: 异常处理模块
  • urllib.parse: url解析模块
  • urllib.robotparser: robots.txt解析模块

urllib模块用来爬虫其实不是很好用,它是一个比较老的模块。在它的基础上有一个新的模块叫:request模块更加好用。但是作为一个基本的模块,还是要好好了解。

① 基本url请求

urlopen的get请求(第一个参数的使用)

先认识一个urllib.request模块中最基本的一个函数:“urlopen()函数”。它主要用于打开一个URL地址帮助我们给服务器发送一个请求。

该函数语法如下:

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

参数说明:

  • url:要打开的URL地址。
  • data(可选):要发送的数据。如果设置了该参数,则会使用POST请求方式发送数据;否则,默认使用GET请求方式。
  • timeout(可选):超时时间,单位为秒。如果连接或读取超时,则抛出异常。如果不指定超时时间,默认情况下会一直等待服务器响应。
  • cafile(可选):用于验证SSL证书的CA证书文件。
  • capath(可选):用于验证SSL证书的CA证书路径。
  • cadefault(可选):是否使用默认的CA证书验证。
  • context(可选):SSL上下文。

urlopen()函数会返回一个类似文件的对象,可以像操作文件一样对其进行读取和处理。例如,可以使用read()方法读取响应内容,使用getcode()方法获取HTTP状态码,使用getheaders()方法获取响应头信息等。

import urllib.request

response = urllib.request.urlopen('http://www.baidu.com')
print(response.read().decode('utf-8'))

结果:
代码执行的结果是上面网址的html代码

urlopen函数的post请求(第二个参数的使用)

再来认识另一个函数。
urllib.parse 是 Python 中用于解析 URL 的标准库模块,提供了一些实用的函数和类来操作 URL。

该模块包含以下功能:

  • urlparse:将 URL 字符串解析成 6 个部分组成的元组,包括 scheme、netloc、path、params、query 和 fragment。
  • urlunparse:与 urlparse 功能相反,将一个 6 元组转换成 URL 字符串。
  • urlsplit:与 urlparse 类似,但只返回 5 个部分的元组,不包括 params。
  • urlunsplit:与 urlunparse 类似,但只接受一个包含 5 个部分的元组。
  • urlencode:将一个字典对象转换为 URL 编码的字符串。
  • quote 和 quote_plus:对 URL 中的特殊字符进行编码,其中 quote_plus 还会将空格转换为加号。
  • unquote 和 unquote_plus:对 URL 编码的字符串进行解码,其中 unquote_plus 还会将加号转换为空格。

所以:urllib.parse.urlencode 是 Python 中的一个函数,用于将字典对象转换为 URL 编码的字符串。
具体来说,它将字典对象中的键值对按照 key1=value1&key2=value2 的格式进行拼接,并进行 URL 编码。

import urllib.parse
import urllib.request

data = bytes(urllib.parse.urlencode({
   'word': 'hello'}), encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post', data=data)
print(response.read())

说明:
http://httpbin.org是一个专门供开发者进行HTTP测试的网址,关于它的使用参考:https://blog.csdn.net/m0_58656539/article/details/127321217
上述代码就是对http://httpbin.org/post网址进行post请求并传入一个参数。
所以结果form表单里增加了我们传入的参数。

urlopen函数的timeout参数(第三个参数的使用)

import socket
import urllib.request
import urllib.error

try:
    response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')
        
说明:
上述try下面代码如果出现超时就会报urllib.error.URLError错误。
如果发生了 URLError 异常,我们使用 isinstance() 函数检查 e.reason 是否是 socket.timeout 类型的对象。如果是,说明发生了超时错误。
在 urllib.error 模块中,当发生网络请求超时时,会引发 URLError 异常,并将超时错误的原因存储在 reason 属性中。而在 socket 模块中,socket.timeout 是用于表示网络请求超时的异常类。
isinstance() 是 Python 内置函数之一,用于检查一个对象是否是指定类或其子类的实例。

② 查看http请求的响应信息

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(type(response))	# 输出响应类型
print(response.status)	# 输出响应状态码
print(response.getheaders())	# 输出响应头信息
print(response.getheader('Server'))	# 输出响应头Server信息

结果:
<class 'http.client.HTTPResponse'>
200
[('Connection', 'close'), ('Content-Length', '51167'), ('Report-To', '{"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1705569764&sid=67ff5de4-ad2b-4112-9289-cf96be89efed&s=8Pjqu5Qjh5kk00GkE%2FtctVoCTr%2BYJDoO4I%2BYiwcooqk%3D"}]}'), ('Reporting-Endpoints', 'heroku-nel=https://nel.heroku.com/reports?ts=1705569764&sid=67ff5de4-ad2b-4112-9289-cf96be89efed&s=8Pjqu5Qjh5kk00GkE%2FtctVoCTr%2BYJDoO4I%2BYiwcooqk%3D'), ('Nel', '{"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}'), ('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'SAMEORIGIN'), ('Via', '1.1 vegur, 1.1 varnish, 1.1 varnish'), ('Accept-Ranges', 'bytes'), ('Date', 'Thu, 18 Jan 2024 09:58:53 GMT'), ('Age', '2160'), ('X-Served-By', 'cache-iad-kiad7000025-IAD, cache-nrt-rjtf7700050-NRT'), ('X-Cache', 'HIT, HIT'), ('X-Cache-Hits', '3, 848'), ('X-Timer', 'S1705571934.524562,VS0,VE0'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')]
nginx

③ 另一个请求方法:Request

urllib.request 模块中的 urllib.request.Request() 方法用于创建一个 HTTP 请求对象,可以在请求中指定 URL、请求方法、请求头部信息和请求体数据等参数。

该方法的语法如下:

urllib.request.Request(url, data=None, headers={
   }, origin_req_host=None, unverifiable=False, method=None)

其中,各参数的含义如下:

  • url:必填,需要请求的 URL 地址。
  • data:选填,需要在请求中传递的数据。如果不需要传递数据,可以将其设为 None。
  • headers:选填,指定请求头部信息。默认为空字典。
  • origin_req_host:选填,指定原始请求主机名,用于处理 HTTP 重定向。默认为 None。
  • unverifiable:选填,指定请求是否可验证。默认为 False。
  • method:选填,指定 HTTP 请求方法。如果不指定,则默认使用 GET 方法。

他跟之前的方法urlopen是有一些区别的:

  • 功能不同:
    • urllib.request.urlopen():用于发送 HTTP/HTTPS 请求并获取响应内容。
    • urllib.request.Request():用于创建一个 HTTP 请求对象,但并不直接发送请求或获取响应。
    • 之前的urlopen方法不能设置响应头等等信息,Request方法就比较全面了。
  • 使用方式不同:
    • urllib.request.urlopen() 是一个函数,直接调用即可发送请求和获取响应。示例:response = urllib.request.urlopen(url)
    • urllib.request.Request() 是一个类,需要使用该类的实例来创建一个请求对象,然后通过 urlopen() 方法发送请求并获取响应。示例:req = urllib.request.Request(url) 和 response = urllib.request.urlopen(req)
  • 参数传递方式不同:
    • urllib.request.urlopen() 直接接受 URL 字符串作为参数,可以额外传递一些参数如超时时间、代理等。
    • urllib.request.Request() 的参数更为灵活,可以指定 URL、请求方法、请求头部信息、请求体数据等多个参数。

示例

from urllib import request, parse

url = 'http://httpbin.org/post'
headers = {
   
    'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
    'Host': 'httpbin.org'
}
dict = {
   
    'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

# ----------------------------------------------

from urllib import request, parse

url = 'http://httpbin.org/post'
dict = {
   
    'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

# 说明:
# 上面代码通过Request方法传入了url、data、headers、method等参数。构建了一个请求对象。
# 还可以通过add_header方法向请求对象添加header参数。

④ Handler 处理请求和响应 & Cookie 存储用户信息

按照前面的方法可以爬取大部分的网页了,但还有一些高级用法,比如设置Handler代理,设置Cookie等。

Handler

在 Python 的 urllib.request 模块中,Handler 是一种处理器,用于处理特定类型的请求或响应。它是一个抽象基类,提供了一些方法和属性,可以根据需要进行子类化和自定义。
常见的 Handler 类包括 ProxyHandler、HTTPHandler、HTTPSHandler、FileHandler 等。

  • ProxyHandler:用于设置代理服务器,将请求转发到代理服务器进行访问。
  • HTTPHandler:处理 HTTP 请求的默认处理器。
  • HTTPSHandler:处理 HTTPS 请求的默认处理器。与 HTTPHandler 类似,但支持 SSL 加密。
  • FileHandler:用于处理本地文件的处理器。
import urllib.request

proxy_handler = urllib.request.ProxyHandler({
   
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})
opener = urllib.request.build_opener(proxy_handler)
response = opener.open('http://httpbin.org/get')
print(response.read())

#说明:
这段代码是使用Python的urllib库来发送HTTP请求,并通过设置代理服务器来访问一个网址。
首先,我们导入了urllib.request模块,它提供了发送HTTP请求的功能。
然后,我们创建了一个代理处理程序(ProxyHandler),它告诉我们要使用代理服务器来发送请求。代理服务器是一个中间服务器,可以帮助我们访问其他网站。
ProxyHandler是urllib.request模块提供的一个处理器类,它允许你在请求中指定代理服务器。构造ProxyHandler对象时,你需要传入一个字典作为参数,其中包含了不同协议对应的代理服务器地址。
在你的代码中,字典中有两个键值对:'http': 'http://127.0.0.1:59242':表示使用HTTP协议时要使用的代理服务器地址是http://127.0.0.1:59242'https': 'https://127.0.0.1:59242':表示使用HTTPS协议时要使用的代理服务器地址是https://127.0.0.1:59242'''这个端口是代理服务器的端口'''
通过将这个ProxyHandler对象传递给build_opener()函数,创建了一个自定义的URL打开器opener。这个opener会在发送请求时使用你指定的代理服务器以及其他的一些设置。
当你调用opener.open('https://www.baidu.com/')时,它会使用配置好的代理服务器向https://www.baidu.com/发送GET请求,并返回响应。

Cookie

cookie是在客户端保存的,一种用来记录用户身份的文本文件。
详细来说
Cookie是一种在客户端(如浏览器)和服务器之间传递的小型数据文件。

它由服务器生成并发送给客户端,然后客户端将其存储,并在每次向服务器发送请求时将其包含在请求中。Cookie通常用于实现会话管理和状态跟踪。服务器可以使用Cookie来存储和检索有关用户的信息,以便在不同的HTTP请求之间保持会话状态。例如,当你登录一个网站时,服务器可能会生成一个包含用户身份验证信息的Cookie,并将其发送给你的浏览器。浏览器会将Cookie保存下来,在以后的请求中自动包含该Cookie,这样服务器就能够识别你并维持你的登录状态。

Cookie可以包含各种信息,例如用户ID、购物车内容、用户首选项等。它们可以被服务器读取和修改,但只能由与生成Cookie的服务器具有相同域名的服务器进行访问。此外,Cookie还可以设置过期时间,以控制其有效期。

虽然Cookie在提供了方便的会话管理和状态跟踪功能的同时,也存在一些安全和隐私方面的考虑。因此,浏览器通常提供了一些设置选项,让用户可以选择是否接受或删除Cookie,并限制Cookie的使用。

#示例1:
import http.cookiejar, urllib.request

cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
    print(item.name+"="+item.value)
    
'''
说明:
这段代码的作用是使用http.cookiejar模块与urllib.request模块来获取并打印访问百度网站时返回的 Cookie。
首先,我们创建了一个CookieJar对象来存储 Cookie。然后,我们创建了一个HTTPCookieProcessor对象,并将其与CookieJar对象进行绑定。接下来,我们使用build_opener方法创建了一个自定义的OpenerDirector对象,并将CookieHandler传递给它。这样做是为了使用包含 Cookie 的请求进行访问。

CookieJar是一个容器,用于存储和管理HTTP请求和响应中的Cookie的类。
HTTPCookieProcessor也是一个Handler处理器,用于自动处理HTTP请求和响应中的Cookie。
简而言之,HTTPCookieProcessor是处理Cookie的工具,而CookieJar是存储和管理Cookie的容器。它们可以结合使用,实现方便的Cookie管理和跟踪功能。

总结:这一段代码跟上一段很像。都是先制作一个handler处理器,上面是处理代理服务器的,这个是处理cookie的。而且这个处理器绑定了一个cookie容器。然后同样去创建一个url启动器opener,去打开指定的网址
'''

#示例2:
import http.cookiejar, urllib.request
filename = "cookie.txt"
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)

'''
说明:
CookieJar类是一个通用的cookie容器,可以保存所有类型的cookie,而MozillaCookieJar类则是一个特定类型的cookie容器,只能保存Mozilla浏览器(如Firefox)生成的cookie。
该对象可以将cookie保存到本地文件中。在创建MozillaCookieJar对象时,需要指定一个文件名,以便将cookie保存到该文件中。

CookieJar有很多的子类,CookieJar类以及其子类(例如LWPCookieJar和MozillaCookieJar)提供了许多有用的方法和属性,用于加载、保存和管理cookie信息。
'''

⑤ 异常处理

error是Python标准库中urllib模块中包含的一个模块,用于表示与URL操作相关的错误。
在error模块中包含了多个异常类,用于表示不同类型的URL操作错误。其中比较常用的异常类包括:

error中的异常类名 描述说明
URLError 表示与URL相关的错误,例如网络连接问题、DNS查询失败、URL格式错误等。
HTTPError 表示HTTP请求返回的错误状态码,例如404 Not Found、500 Internal Server Error等。
ContentTooShortError 表示下载的内容过短,可能是由于网络连接中断等原因导致的。
HTTPWarning 表示HTTP响应中包含了警告信息,例如缺失的响应头部字段等。

python中的异常捕获语句
格式:

try:
    # 可能会抛出异常的代码块
except ExceptionType1 as e1:
    # 处理 ExceptionType1 类型的异常
except ExceptionType2 as e2:
    # 处理 ExceptionType2 类型的异常
except:
    # 处理其他类型的异常
else:
    # 如果没有发生异常,执行的代码块
finally:
    # 无论是否发生异常,都会执行的代码块

示例:

# 1
from urllib import request, error
try:
    response = request.urlopen('http://www.baidu.com')
except error.URLError as e:
    print(e.reason)
# 上述代码使用了urllib模块中的request和error子模块,并结合try-except语句来处理URL操作可能出现的异常。
# e.reason属性返回一个字符串,其中包含了引起异常的具体原因

# 2
from urllib import request, error

try:
    response = request.urlopen('http://www.baidu.com')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers, sep='\n')
except error.URLError as e:
    print(e.reason)
else:
    print('Request Successfully')
# 刚才的代码只处理了error.URLError异常,而这段代码处理了两种类型的异常:error.HTTPError和error.URLError。
# 这段代码使用了两个except语句块,分别捕获error.HTTPError和error.URLError异常。在发生异常时,会根据异常的类型执行对应的except语句块。如果没有发生异常,则会执行else语句块,表示请求成功。
# 此外,error.HTTPError异常类还提供了reason、code和headers等属性,用于获取错误原因、状态码和响应头信息。在捕获到该异常时,可以使用这些属性来详细了解HTTP请求返回的错误信息。
    
# 3
import socket
import urllib.request
import urllib.error

try:
    response = urllib.request.urlopen('https://www.baidu.com', timeout=0.01)
except urllib.error.URLError as e:
    print(type(e.reason))
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')
# 这段代码与刚才的代码相比,只捕获了error.URLError异常,并且增加了对超时异常的处理。当URL请求超时时,会打印'TIME OUT'。
# isinstance()函数判断e.reason是否是socket.timeout类型的异常,如果是,则打印'TIME OUT'。
# 知识点补充:
# socket.timeout是在Python中用于表示套接字超时的异常类型。当套接字在指定的时间内没有响应时,将引发此异常。
# isinstance()是Python内置函数之一,用于检查一个对象是否是指定类或其子类的实例。它的语法格式如下:isinstance(object, classinfo)

⑥ url解析

urlparse

urlparse是Python标准库中urllib.parse模块提供的一个函数,用于解析URL(统一资源定位符)字符串,并将其拆分为不同的组成部分。它的作用是方便地对URL进行解析和提取信息。

urlparse函数的语法如下:
urllib.parse.urlparse(urlstring, scheme=‘’, allow_fragments=True)

其中,urlstring是要解析的URL字符串,scheme是可选的默认协议(前提是URL字符串没有指定协议),allow_fragments表示是否允许片段标识符(即#后面的部分)。
urlparse函数将URL字符串解析为一个包含以下属性的命名元组(namedtuple):

  • scheme:协议(如http、https等)
  • netloc:网络位置,通常是主机名和端口号
  • path:路径部分
  • params:参数部分
  • query:查询字符串部分
  • fragment:片段标识符部分

举例:

from urllib.parse import urlparse

result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result), result)
print(result.scheme)
print(result.netloc)
print(result.path)

# 结果:
# <class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
# http
# www.baidu.com
# /index.html

# 示例2:
from urllib.parse import urlparse

result = urlparse('http://www.baidu.com/index.html#comment', scheme='https',allow_fragments=False)
print(result)

# 结果:
# ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html#comment', params='', query='', fragment='')

urlunparse

urlunparse 是 Python 标准库中的一个函数,跟urlparse相反,用于将 URL 元组(由以下 6 个部分组成:协议、网络位置、路径、参数、查询字符串和片段标识符)转换回 URL 字符串。函数定义如下:

urllib.parse.urlunparse(parts)

其中,参数 parts 是一个包含 6 个元素的元组,分别对应 URL 的各个部分。如果某些部分没有值,则可以使用空字符串表示。

举例:

from urllib.parse import urlunparse

data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))

# 结果:
# http://www.baidu.com/index.html;user?a=6#comment

urljoin

urljoin 是 Python 标准库中 urllib.parse 模块提供的一个函数,用于将一个基础 URL 和一个相对 URL 进行合并,生成一个完整的 URL。

相对 URL 是相对于基础 URL 的路径,可以是一个相对路径(如 /path/to/resource)或一个带有协议和网络位置的相对 URL(如 http://www.example.com/path/to/resource)。urljoin 函数会将这两个 URL 进行合并,生成最终的 URL。

urllib.parse.urljoin(base, url)

其中,base 参数是基础 URL,url 参数是相对 URL。urljoin 会根据这两个 URL 的关系进行合并,并返回合并后的结果。

from urllib.parse import urljoin

print(urljoin('http://www.baidu.com', 'aaa.html'))
print(urljoin('http://www.baidu.com', 'https://www.bilibili.com/aaa.html'))
print(urljoin('http://www.baidu.com/aaa.html', 'https://www.bilibili.com/bbb.html'))
print(urljoin('http://www.baidu.com/aaa.html', 'https://www.bilibili.com/bbb.html?question=2'))
print(urljoin('http://www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com#comment', '?category=2'))
print(urljoin('http://www.baidu.com#comment', '?category=2'))
# 说明:
# http://www.baidu.com/aaa.html
# https://www.bilibili.com/aaa.html
# https://www.bilibili.com/bbb.html
# https://www.bilibili.com/bbb.html?question=2
# http://www.baidu.com?category=2#comment
# www.baidu.com?category=2#comment
# www.baidu.com?category=2
# http://www.baidu.com?category=2
# 最后一句说明:在URL中,#符号表示片段标识符(Fragment),用于指定页面中的特定部分或锚点。在使用 urljoin 函数合并URL时,如果相对URL中包含了查询字符串(?category=2),那么它会替换基础URL中的查询字符串,同时也会去掉基础URL中的片段标识符。

urlencode

urlencode 是 Python 标准库中的 urllib.parse 模块提供的一个函数,用于将字典或具有类似结构的可迭代对象转换为 URL 编码的查询字符串。

格式:

urllib.parse.urlencode(query, doseq=False, safe='', encoding=None, errors=None, quote_via=quote_plus)
  • query 参数是一个字典或可迭代对象,表示要编码的查询参数。
  • doseq 参数(默认为 False)指示是否处理具有相同键的多个值。
  • safe 参数指定不需要进行编码的字符集合。
  • encoding 参数指定编码方式,默认为 UTF-8。
  • errors 参数指定在编码过程中遇到错误时的处理方式。
  • quote_via 参数指定引用方式,默认为 quote_plus,即使用加号替换空格。

举例:

from urllib.parse import urlencode

params = {
   
    'name': 'germey',
    'age': 22
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)

# 结果:http://www.baidu.com?name=germey&age=22

2 Requests库的基本使用

urllib库虽然可以完成很多操作,但是实现起来还是有点不太方便的。比如添加代理、处理cookie等。
requests是一个更加强大的库,有了它可以使用几句代码就可以完成很多功能。

requests是一个常用的 Python 第三方库,用python语言编写,基于urllib,采⽤Apache2 Licensed 开源协议的 HTTP 库。用于发送 HTTP 请求和处理响应。它提供了简洁而直观的 API,使得 HTTP 请求变得容易。

它比 urllib 更更加⽅方便便,可以节约我们⼤大量量的⼯工作,完全满⾜足HTTP 测试需求。
一句话——Python实现的简单易易⽤用的HTTP库

① 模块的简单使用

通过一个例子来简单说一下requests模块的使用。

import requests

response = requests.get('https://www.baidu.com/')
print(type(response))
print(response.status_code)
print(type(response.text))
print(response.text)
print(response.cookies)

# 说明:
# 这段代码使用了 Python 的 requests 库发送了一个 GET 请求到百度网站,并输出了一些请求的返回信息。

② requests模块的各种请求方式

import requests
requests.post('http://httpbin.org/post')
requests.put('http://httpbin.org/put')
requests.delete('http://httpbin.org/delete')
requests.head('http://httpbin.org/get')
requests.options('http://httpbin.org/get')

# 说明:这段代码演示了使用 requests 库发送不同类型的 HTTP 请求

当我们在进行网络通信时,常用的HTTP请求方法有GET、POST、PUT、DELETE、HEAD和OPTIONS。
接下来详细解释一下每种请求的作用和特点:

  • GET
    • 作用:从指定的资源请求数据。
    • 特点:一般用于从服务器获取数据,请求参数附加在URL后面,可以被缓存,有长度限制。
  • POST
    • 作用:向指定的资源提交要被处理的数据。
    • 特点:一般用于向服务器发送数据,请求参数附加在请求体中,不会被缓存,没有长度限制,安全性更好。
  • PUT
    • 作用:向指定的资源位置上传最新内容。
    • 特点:类似于POST,但在语义上更加明确,通常用于更新数据。
  • DELETE
    • 作用:从指定的资源位置删除内容。
    • 特点:用于删除指定的资源。
  • HEAD
    • 作用:类似于GET请求,只是返回的响应中没有具体的内容,用于获取资源的元信息。
    • 特点:可以用于检查资源是否存在、资源是否被修改等,而不需要获取整个资源内容。
  • OPTIONS:
    • 作用:用于获取目的URL所支持的HTTP方法。
    • 特点:可以用于跨域请求时的预检请求,以确定是否可以在实际请求中使用某个HTTP方法。

这些HTTP请求方法各自具有不同的作用和特点,根据实际需求选择合适的请求方法可以更好地完成网络通信任务。

接下来从几个方面讲述requests模块的用法详情

③ 请求

基本GET请求

基本写法:

import requests

response = requests.get('http://httpbin.org/get')
print(response.text)

带参数GET请求

# 1:
import requests
response = requests.get("http://httpbin.org/get?name=germey&age=22")
print(response.text)

# 2:
import requests

data = {
   
    'name': 'germey',
    'age': 22
}
response = requests.get("http://httpbin.org/get", params=data)
print(response.text)

# 说明:
# 1和2是一样的,不过实际应用中都会用2方法,方便修改
# 1中 ?name=germey&age=22:表示请求的查询参数,以 ? 开头,多个参数之间使用 & 进行分隔
# 2中 参数也可以以字典的形式保存,通过params参数传到get方法

解析json数据和str数据

import requests
import json

response = requests.get("http://httpbin.org/get")
print(type(response.text))
print(response.json())
print(json.loads(response.text))
print(type(response.json()))

# 说明:
# 上面的代码中,先用get方法请求指定网址,并将返回的响应保存在 response 变量中。
# 然后通过response.text方法获取响应内容的字符串格式数据
# response.json()方法是将返回的响应内容解析为 JSON 格式
# json.loads()方法用于将 JSON 格式的字符串转换为 Python 对象(通常是字典或列表)

解析获取二进制数据

先认识一下requests中的两个语句的区别:
response.content 和 response.text 是 requests 库中 Response 对象的两个属性,用于获取响应内容。

返回数据类型方面:

  • response.content 返回响应内容的字节形式(bytes)。
  • response.text 返回响应内容的字符串形式(str),使用响应内容的编码来解码为字符串。

另外编码方面:

  • response.content 不会对内容进行任何解码或编码处理,直接返回原始的字节数据。
  • response.text 会根据服务器返回的响应头中的编码信息(如 “Content-Type” 的 charset 属性)自动进行解码,将字节数据转换为字符串。如果无法确定编码类型,则会使用 UTF-8 进行解码。

使用场景方面:

  • response.content 适合处理非文本文件,如图片、音频、视频等二进制数据。你可以将这些数据保存到文件或进行其他的二进制处理。
  • response.text 适合处理文本数据,如 HTML、JSON、XML 等。你可以对文本数据进行字符串操作、解析或提取所需的信息。
import requests

response = requests.get("https://github.com/favicon.ico")
print(type(response.text), type(response.content))
print(response.text)
print(response.content)

添加headers

为什么要添加headers?

在发送 HTTP 请求时,服务器会根据请求的 User-Agent 头信息来判断发出请求的客户端类型和版本。如果该头信息缺失或不正确,服务器可能会拒绝提供服务,并返回错误响应。

一些网站会针对不同的 User-Agent 信息返回不同的响应内容,例如移动设备版和桌面版的网站页面可能是不同的。在这种情况下,如果没有正确设置 User-Agent 头信息,可能会导致获取到不需要的响应内容或者被服务器拒绝访问。

# 例子:
import requests

headers = {
   
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
response = requests.get("https://www.zhihu.com/explore", headers=headers)
print(response.text)

在以上的代码中,我们使用了 requests 库发送了一个 GET 请求,其中将 headers 参数设置为指定的 User-Agent 头信息。这样可以伪装成浏览器向服务器发送请求,避免被服务器拒绝或获取到错误的响应内容。

总之,添加 User-Agent 头信息可以提高请求的成功率并确保获取到正确的响应内容。

基本POST请求

POST 请求是一种 HTTP 请求方法,主要用于向服务器提交数据,比如表单数据、JSON 数据等。与 GET 请求不同,POST 请求将请求参数放在请求体中,而不是 URL 中。

POST 请求通常用于向服务器提交数据,比如用户登录、注册、提交表单数据等操作。例如,用户登录时需要向服务器发送用户名和密码,这就可以通过 POST 请求将用户输入的数据提交到后端服务器进行验证和处理。

此外,POST 请求还支持上传文件等功能。可以使用 POST 请求将文件数据提交到服务器,以实现文件上传功能。

综上所述,POST 请求是一种非常常见的 HTTP 请求方法,用于向服务器提交数据或上传文件等操作。如果你需要向服务器传递数据或上传文件,那么就需要发送一个 POST 请求。

# 举例:
import requests

data = {
   'name': 'germey', 'age': '22'}
headers = {
   
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
response = requests.post("http://httpbin.org/post", data=data, headers=headers)
print(response.json())

# 注意:对于 requests.post 方法中的 data 参数,它会被自动编码并作为请求体的内容发送到服务器。

④ 响应

response属性

在使用 requests 库发送请求后,返回的响应对象 response 中包含了许多有用的信息,包括:

  • status_code:响应的状态码,如 200 表示成功,404 表示未找到资源,500 表示服务器错误
  • text:响应的内容(Unicode 格式)。
  • content:响应的内容(字节流格式)。
  • headers:响应头信息,是一个字典类型,包含了响应的各种元数据,比如 Content-Type、Content-Length 等。
  • cookies:响应的 Cookie 信息,是一个字典类型,包含了响应中的所有 Cookie 信息。
  • url:响应的 URL地址,可能会发生重定向。
  • encoding:响应的编码方式。
  • history:它是一个列表,包含了请求的历史记录。
    • 当发送请求时,如果遇到了重定向(3xx 状态码),requests 会自动处理重定向,并将每个重定向的请求添加到 history 列表中。通过查看 history 列表,你可以获取请求的完整重定向历史记录。
    • 需要注意的是,response.history 列表中的第一个元素代表初始请求,后续元素代表对应的重定向请求。因此,如果没有发生重定向,response.history 列表会为空。
    • 如果你想禁止 requests 自动处理重定向,可以设置 allow_redirects=False 参数,这样 response.history 列表将为空,而响应对象中的 status_code 将是最终请求的状态码。
import requests

response = requests.get('http://www.jianshu.com')
print(type(response.status_code), response.status_code)
print(type(response.headers), response.headers)
print(type(response.cookies), response.cookies)
print(type(response.url), response.url)
print(type(response.history), response.history)

状态码判断

为什么要进行状态码的判断?

在网络请求中,状态码是服务器对请求的响应进行分类和传达信息的一种方式。通过检查状态码,我们可以了解服务器对请求的处理情况,例如是否成功、是否发生重定向、资源是否存在等。

常见的状态码有:

  • 2xx:表示成功处理请求,如 200 表示成功,201 表示创建成功等。
  • 3xx:表示重定向,如 301 表示永久重定向,302表示临时重定向等。
  • 4xx:表示客户端错误,如 404 表示资源未找到,403 表示禁止访问等。
  • 5xx:表示服务器错误,如 500表示服务器内部错误,503 表示服务不可用等。

可以根据状态码和描述信息来判断请求的处理结果,并采取相应的处理措施。例如,当状态码为 200 时,可以继续处理返回的数据;当状态码为 404 时,可以提示用户请求的资源不存在;当状态码为 500 时,可以向用户显示服务器内部错误的提示信息。

请注意,这只是常见状态码的一部分,实际上还有更多的状态码可供使用。在实际开发中,我们可以根据不同的业务需求和场景来选择适当的状态码。

# 1.
import requests

response = requests.get('http://www.jianshu.com/hello.html')
exit() if not response.status_code == requests.codes.not_found else print('404 Not Found')

# 说明:
# 1.格式:操作1 if 条件 else 操作2   解释:如果 条件 为真,执行 操作1;否则执行 操作2。
# 2.requests.codes.not_found 是 requests 库中定义的表示 404 的常量

# 2.
import requests

response = requests.get('http://www.jianshu.com')
exit() if not response.status_code == 200 else print('Request Successfully')

状态码及其含义:

100: ('continue',),
101: ('switching_protocols',),
102: ('processing',),
103: ('checkpoint',),
122: ('uri_too_long', 'request_uri_too_long'),
200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'),
201: ('created',),
202: ('accepted',),
203: ('non_authoritative_info', 'non_authoritative_information'),
204: ('no_content',),
205: ('reset_content', 'reset'),
206: ('partial_content', 'partial'),
207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'),
208: ('already_reported',),
226: ('im_used',),

# Redirection.
300: ('multiple_choices',),
301: ('moved_permanently', 'moved', '\\o-'),
302: ('found',),
303: ('see_other', 'other'),
304: ('not_modified',),
305: ('use_proxy',),
306: ('switch_proxy',),
307: ('temporary_redirect', 'temporary_moved', 'temporary'),
308: ('permanent_redirect',
      'resume_incomplete', 'resume',), # These 2 to be removed in 3.0

# Client Error.
400: ('bad_request', 'bad'),
401: ('unauthorized',),
402: ('payment_required', 'payment'),
403: ('forbidden',),
404: ('not_found', '-o-'),
405: ('method_not_allowed', 'not_allowed'),
406: ('not_acceptable',),
407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'),
408: ('request_timeout', 'timeout'),
409: ('conflict',),
410: ('gone',),
411: ('length_required',),
412: ('precondition_failed', 'precondition'),
413: ('request_entity_too_large',),
414: ('request_uri_too_large',),
415: ('unsupported_media_type', 'unsupported_media', 'media_type'),
416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'),
417: ('expectation_failed',),
418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'),
421: ('misdirected_request',),
422: ('unprocessable_entity', 'unprocessable'),
423: ('locked',),
424: ('failed_dependency', 'dependency'),
425: ('unordered_collection', 'unordered'),
426: ('upgrade_required', 'upgrade'),
428: ('precondition_required', 'precondition'),
429: ('too_many_requests', 'too_many'),
431: ('header_fields_too_large', 'fields_too_large'),
444: ('no_response', 'none'),
449: ('retry_with', 'retry'),
450: ('blocked_by_windows_parental_controls', 'parental_controls'),
451: ('unavailable_for_legal_reasons', 'legal_reasons'),
499: ('client_closed_request',),

# Server Error.
500: ('internal_server_error', 'server_error', '/o\\', '✗'),
501: ('not_implemented',),
502: ('bad_gateway',),
503: ('service_unavailable', 'unavailable'),
504: ('gateway_timeout',),
505: ('http_version_not_supported', 'http_version'),
506: ('variant_also_negotiates',),
507: ('insufficient_storage',),
509: ('bandwidth_limit_exceeded', 'bandwidth'),
510: ('not_extended',),
511: ('network_authentication_required', 'network_auth', 'network_authentication')

⑤ 高级操作

文件上传

import requests

files = {
   'file': open('favicon.ico', 'rb')}
response = requests.post("http://httpbin.org/post", files=files)
print(response.text)

可以使用post方法向服务器提交数据,POST不仅可以提交简单的键值对数据,还可以上传文件和传输大量数据。

requests.post() 方法是 Python requests 库中用于发送 HTTP POST 请求的函数。这个方法非常灵活,提供了多个参数来定制请求。以下是 requests.post() 方法支持的常见参数及其说明:

  • url (str): 请求的URL。
  • data (optional, dict, bytes, or file-like object): 要发送到URL的正文数据。如果是字典类型,数据会被自动编码为表单形式。
  • json (optional, dict): JSON格式的数据,如果指定了这个参数,requests 会自动将其序列化为JSON字符串,并设置Content-Type为application/json。
  • headers (optional, dict): 字典类型的请求头。可以在这里指定请求头部信息,如Content-Type、User-Agent等。
  • cookies (optional, dict or CookieJar): 要随请求发送的Cookies。
  • files (optional, dict): 文件上传。字典中的键是服务器端识别的表单字段名,值是要上传的文件。值可以是一个元组(filename, fileobj),也可以是一个元组(filename, fileobj, content_type),还可以是一个元组(filename, fileobj, content_type, custom_headers)。
  • timeout (optional, float or tuple): 设置请求超时时间,以秒为单位。可以是一个浮点数,表示连接和读取的总超时时间;也可以是一个元组(connect_timeout, read_timeout)分别指定连接和读取的超时时间。

获取cookie

import requests

response = requests.get("https://www.baidu.com")
print(response.cookies)
for key, value in response.cookies.items():
    print(key + '=' + value)
# 说明:
# 这段Python代码使用了requests库来发送一个HTTP GET请求到百度的主页("https://www.baidu.com"),然后打印出从响应中获得的cookies信息。
# response.cookies属性包含了服务器通过Set-Cookie头部发送回来的所有cookies。这个属性是一个RequestsCookieJar对象,它提供了一个字典接口,可以像操作字典那样操作cookies。

# 总结:
# 整个代码的作用是向百度的主页发送一个HTTP GET请求,获取响应中的cookies,并打印出每个cookie的名称和值。这对于理解如何使用requests库处理cookies,以及如何从HTTP响应中获取和查看特定信息(如cookies)非常有帮助。
# Cookies通常用于服务器识别或跟踪访问者的状态,例如用户登录状态、偏好设置等。通过查看响应中的cookies,开发人员可以了解网站是如何配置和使用cookies的。

会话维持

有了cookies就可以来完成会话维持、以及保持登陆状态的操作了

模拟登录

import requests

requests.get('http://httpbin.org/cookies/set/number/123456789')
response = requests.get('http://httpbin.org/cookies')
print(response.text)

# 结果:
{
   
  "cookies": {
   }
}
# 说明:
# 这段代码展示了如何使用Python的requests库来首先设置一个cookie,然后获取该cookie。具体来说,它通过两次对httpbin.org的GET请求演示了这一过程,我们可以理解为用一个浏览器设置cookie,再用下一个浏览器获取,两个操作是独立的。想要完成模拟登录,两次请求应该在一个浏览器中完成。
import requests

s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
response = s.get('http://httpbin.org/cookies')
print(response.text)

# 结果:
{
   
  "cookies": {
   
    "number": "123456789"
  }
}
# 说明:
# Session对象是requests库中的一个特殊对象,用于在多个HTTP请求之间保持某些参数的状态,例如cookies、headers等。使用Session对象可以方便地管理和维护这些参数,而不需要每次请求都重新设置它们。
# 使用Session对象,设置的cookie将会在这个会话中被保留,并且在第二个请求中正确返回

使用Session对象的主要好处包括:

  • 自动处理cookies:Session对象会自动在每个请求中管理cookie的发送和接收。当你使用Session对象发送请求时,它会自动跟踪并存储来自服务器的任何cookie,并在后续的请求中自动将cookie添加到请求中。
  • 共享参数和状态:Session对象可以在多个请求之间共享参数和状态。例如,你可以在第一个请求中设置headers,然后在后续的请求中重复使用相同的headers,而无需每次请求都重新设置。
  • 提高性能:使用Session对象可以更高效地执行多个请求。它会自动重用底层的TCP连接,从而减少了建立和关闭连接的开销,并且可以实现更好的性能。

证书验证

import requests
from requests.packages import urllib3
urllib3.disable_warnings()
response = requests.get('https://www.12306.cn', verify=False)
print(response.status_code)

# 说明:
# 这段代码使用requests库发送了一个GET请求到https://www.12306.cn,并打印了返回的响应状态码。和上一个例子不同的是,在这个例子中,还设置了verify=False参数,并禁用了urllib3警告。
# 通过调用urllib3.disable warnings()方法禁用urllib3警告。这是因为在向HTTPS网站发送请求时,ur11ib3 会发出安全警告,默认情况下这些警告是启用的,通常情况下,这些警告是有用的,可以帮助我们识别可能存在的安全问题。但在某些情况下,例如访问受信任的内部网站或测试环境时,这些警告可能是干扰性的。因此,在这里禁用了它们。
# 接着,使用 reguests.get()方法发送一个GET请求到目标URL,注意到这里还设置了 verify=fa1se 参数,用于关闭SSL证书验证。这是因为一些网站的安全证书可能会过期或无法验证,导致reqpest库无法建立安全连接。在这种情况下,如果你仍然想要向该网站发送请求,可以使用 verify=fa1se参数关闭证书验证。需要注意的是,关闭证书验证可能会带来安全风险,因此建议仅在测试环境中使用。

# from requests.packages import urllib3语句说明:
# 这段代码从requests.packages模块中导入了 urllib3 模块。 urllib3模块是一个独立的HTTP库,用于处理与HITP相关的底层细节,例如连接池管理、请求重试、SSL验证等。reguests 库是基于 ur11ib3 库构建的,因此在使用 requests 库时, ur11ib3 通常是白动加载的,无需手动导入。
# 不过,在某些情况下,我们可能需要直接使用 urllib3库中的一些功能,例如禁用SSL证书验证、关闭警告等。在这种情况下,我们需要手动导入 urllib3 模块,并使用其中的方法和属性需要注意的是,由于 requests 库是基于 urllib3 库构建的,因此在使用 requests库时,也可以通过 requests.packages.urllib3 模块来访问 urllib3 库中的方法和属性,例如,可以使用requests.packages.urllib3.disable_warnings()方法禁用 urllib3 整告。
import requests

response = requests.get('https://www.12306.cn', cert=('/path/server.crt', '/path/key'))
print(response.status_code)解释

# 说明:
# 这段代码使用 requests 库发送了一个 GET 请求到 https://www.12306.cn 网站,并指定了证书文件路径。
# 在这段代码中,cert 参数用于指定客户端的证书文件路径。证书文件通常由一对公私钥组成,分别是 .crt 和 .key 文件。这些证书文件用于与服务器建立安全的 HTTPS 连接。
# 注意:在实际使用时,需要将 /path/server.crt 和 /path/key 替换为实际的证书文件路径。此外,还要确保请求的网站支持客户端证书认证,并且提供了正确的证书文件。

代理设置

之前在urllib3里面用过类似的功能,接下来使用以下requests中的代理设置

import requests

proxies = {
   
  "http": "http://127.0.0.1:9743",
  "https": "https://127.0.0.1:9743",
}

response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)

# 说明:
# 这段代码使用requests库发送一个GET请求到淘宝网,并通过代理服务器进行连接。其中,代理服务器的地址为http://127.0.0.1:9743(HTTP)和https://127.0.0.1:9743(HTTPS)
# 代理字典proxies,其中包含了两个键值对,分别用于指定HTTP和HTTPS代理服务器的地址。

知识补充
requests.get()方法用于发送HTTP GET请求,并可以接受多个参数来自定义请求。

以下是requests.get()方法常用的参数:

  • url(必需):要发送请求的URL地址。
  • params:以字典形式传递的请求参数,将会被拼接到URL中作为查询字符串。
  • headers:以字典形式传递的请求头信息,用于模拟浏览器发送请求时的头部信息。
  • cookies:以字典形式传递的Cookie信息,用于在请求中发送Cookie。
  • auth:用于HTTP身份验证的认证信息,可以使用HTTPBasicAuth等对象进行设置。
  • timeout:设置请求超时时间,单位为秒。如果在指定的时间内没有得到响应,将会引发Timeout异常。
  • allow_redirects:表示是否允许重定向,默认为True。如果设为False,则不会自动处理重定向。
  • proxies:以字典形式传递的代理服务器信息,用于将请求通过代理服务器发送。
  • verify:设置是否验证SSL证书,默认为True。如果设为False,将会跳过SSL证书验证。
  • stream:设置是否使用流式传输,默认为False。如果设为True,可以通过迭代器逐块访问响应内容。
  • params:以字典形式传递的请求参数,将会被拼接到URL中作为查询字符串。
  • 其他可选参数,如cert、proxies、hooks等,用于进一步自定义请求。
import requests

proxies = {
   
    "http": "http://user:password@127.0.0.1:9743/",
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)

# 代码使用了代理服务器来发送HTTP请求。其中,代理服务器的地址为http://127.0.0.1:9743/,并且需要提供用户名和密码进行身份验证。
# 定义了一个代理字典proxies,其中的http键指定了HTTP代理服务器的地址。同时,在地址中,user:password部分是用于代理服务器身份验证的用户名和密码,你需要将它们修改为实际的值。
# 有时候服务器要求客户端提供用户名和密码进行身份验证的情况。当你使用代理服务器时,服务器可以要求客户端提供身份验证信息,以确定是否授权该客户端通过代理服务器访问目标资源。
# 需要注意的是,代理服务器是否要求客户端提供用户名和密码进行身份验证,以及具体的验证方式,都是由服务器配置决定的。某些代理服务器可能不需要身份验证,或者使用其他身份验证方式,如令牌、证书等。因此,在使用代理服务器时,你需要根据实际情况提供正确的身份验证信息。
# 代理服务器需要用户名和密码进行身份验证的原因有以下几点:安全性、访问控制、账单计费、追踪和监视
pip3 install 'requests[socks]'
# pip3 install 'requests[socks]'是安装了名为requests的Python库,并使用了socks附加选项。
# [socks]是一个可选的附加选项,表示安装requests库时包含对SOCKS代理的支持。SOCKS(Socket Secure)是一种网络协议,允许客户端通过代理服务器与远程主机进行通信。通过安装requests[socks],你可以在使用requests库发送请求时选择使用SOCKS代理进行连接。

import requests

proxies = {
   
    'http': 'socks5://127.0.0.1:9742',
    'https': 'socks5://127.0.0.1:9742'
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)

# 这段代码使用requests库发送了一个GET请求到https://www.taobao.com网站,并通过SOCKS代理服务器进行连接。
# 使用HTTP代理可能会导致一些限制,例如不支持所有类型的网络流量,无法达到SOCKS代理的灵活性和安全性等。因此,如果您需要使用SOCKS代理,最好还是安装requests[socks]并使用SOCKS协议进行连接。
使用SOCKS代理相对于HTTP代理有一些优点和特性,这取决于你的具体需求和使用场景。
 - 支持更多的协议:SOCKS代理可以支持TCP、UDP和ICMP等多种协议,而HTTP代理仅支持HTTP协议。如果你需要在应用程序中使用非HTTP协议,例如使用FTP、SMTP、SSH等协议,那么使用SOCKS代理是必要的。
 - 支持远程DNS解析:使用SOCKS代理时,DNS解析通常在代理服务器上进行,可以避免本地DNS污染和泄漏敏感信息。
 - 更高的灵活性:SOCKS代理可以通过代理服务器与远程主机直接建立连接,而不仅仅是通过代理服务器转发HTTP请求。这样可以实现更高级的代理功能,如客户端和服务器之间的双向通信。
 - 更好的安全性:SOCKS代理可以通过身份验证和加密来保护代理连接和传输的数据,提供更高的安全性。
然而,使用SOCKS代理也有一些限制和注意事项:
 - 安装和配置复杂:相对于HTTP代理,设置和配置SOCKS代理可能会更加复杂,需要更多的操作步骤和设置。
 - 不被所有应用程序支持:并非所有的应用程序都直接支持SOCKS代理,特别是一些移动设备上的应用程序可能只支持HTTP代理。

超时设置

import requests
from requests.exceptions import ReadTimeout
try:
    response = requests.get("http://httpbin.org/get", timeout = 0.5)
    print(response.status_code)
except ReadTimeout:
    print('Timeout')
# 这段代码使用了Python的requests库来发送HTTP GET请求。它向"http://httpbin.org/get"发起请求,并设置了一个0.5秒的超时时间。
# 这行代码导入了requests库中的ReadTimeout异常。ReadTimeout是requests库中的一个异常类,它表示请求超时。当requests库在指定时间内未接收到服务器响应时,就会抛出这个异常。
知识补充:
requests库中的exceptions模块提供了一系列异常类,用于处理在使用requests发送HTTP请求时可能出现的各种错误和异常情况。以下是一些常见的异常类:
 - RequestException:是所有requests库异常的基类,用于捕获所有请求相关的异常。
 - HTTPError:在请求返回非成功状态码时引发的异常,如404 Not Found。
 - ConnectionError:当请求遇到网络连接问题时引发的异常,例如DNS解析失败、无法建立连接等。
 - Timeout:在请求超时时引发的异常。 
 - TooManyRedirects:当请求重定向次数过多时引发的异常。 
 - SSLError:在与HTTPS请求相关的SSL验证问题时引发的异常。

认证设置

import requests
from requests.auth import HTTPBasicAuth

r = requests.get('http://120.27.34.24:9001', auth=HTTPBasicAuth('user', '123'))
print(r.status_code)
# 这段代码使用requests库来向"http://120.27.34.24:9001"发送HTTP GET请求,并使用HTTP基本认证对请求进行身份验证。HTTPBasicAuth是requests库中的一个HTTP身份验证类,它提供了基本的用户名和密码验证机制。
# 具体地说,我们通过auth参数传递HTTPBasicAuth('user', '123'),其中'user'和'123'分别表示用户名和密码。这样就可以在请求头中添加Authentication字段,用于身份验证。
知识点补充:
认证设置是在进行网络通信时验证用户身份的一种机制。它用于确保只有经过授权的用户才能访问特定的资源或执行特定的操作。
认证的目的是保护敏感数据和资源,防止未经授权的访问和滥用。通过对用户进行身份验证,系统可以确认用户的身份,并根据其权限决定是否允许其执行请求的操作。
常见的认证方式包括:
 - 基本认证(Basic Authentication):使用用户名和密码进行身份验证,并将其编码后加在请求头中发送给服务器。
 - 摘要认证(Digest Authentication):类似于基本认证,但在传输过程中对密码进行了摘要处理,提高了安全性。
 - 令牌认证(Token Authentication):通过生成和验证令牌来进行身份验证,而不是直接传输用户名和密码。
 - OAuth认证(OAuth Authentication):用于授权第三方应用程序访问用户资源,而无需共享用户名和密码。
认证的主要目的是确保只有合法用户能够访问受限资源,保护用户隐私和数据安全。通过身份验证,系统可以对用户进行身份验证和跟踪,同时也为用户提供了个性化的服务和权限管理。
import requests

r = requests.get('http://120.27.34.24:9001', auth=('user', '123'))
print(r.status_code)

# 这段代码使用requests库向"http://120.27.34.24:9001"发送HTTP GET请求,并使用HTTP基本认证对请求进行身份验证。在这里,我们使用了简化的方式来设置认证,通过auth参数传递元组('user', '123'),其中'user'是用户名,'123'是密码。

总体来说,如果需要更加灵活地控制认证处理过程,建议使用第一种方式;如果只是简单地进行身份验证,可以使用第二种方式。

异常处理

import requests
from requests.exceptions import ReadTimeout, ConnectionError, RequestException
try:
    response = requests.get("http://httpbin.org/get", timeout = 0.5)
    print(response.status_code)
except ReadTimeout:
    print('Timeout')
except ConnectionError:
    print('Connection error')
except RequestException:
    print('Error')
# 这段代码使用requests库发送HTTP GET请求到"http://httpbin.org/get",并设置了一个超时时间为0.5秒。然后,通过try-except语句捕获可能发生的异常。
# 首先,如果在0.5秒内无法得到响应,将触发ReadTimeout异常,代码将打印'Timeout'。
# 其次,如果在建立连接时出现问题,例如网络连接不可用或服务器无响应,将触发ConnectionError异常,代码将打印'Connection error'。
# 最后,如果发生其他请求相关的异常,将触发RequestException异常,代码将打印'Error'。

3 BeautifulSoup库详解

BeautifulSoup是一个灵活又方便的网页解析库,处理高效,支持多种解析器。用于从HTML和XML文件中提取数据。它提供了一种简单的方式来遍历解析HTML或XML文档,并提取所需的信息,例如链接、段落、标题、图片等。

利用它不用编写正则表达式即可方便地实现网页信息的提取,它提供了一组简单的API,使得从HTML和XML文档中提取数据变得更加容易和直观。

在使用BeautifulSoup库时,通常需要先将HTML或XML文档加载到内存中,并使用指定的解析器进行解析。然后,可以使用BeautifulSoup对象提供的方法和属性来查找和提取所需的信息。

① 解析库

BeautifulSoup支持一些解析库,方便我们提取数据

解析器 使用方法 优势 劣势
Python标准库 BeautifulSoup(markup, “html.parser”) Python的内置标准库、执行速度适中 、文档容错能力强 Python 2.7.3 or 3.2.2)前的版本中文容错能力差
lxml HTML 解析器 BeautifulSoup(markup, “lxml”) 速度快、文档容错能力强 需要安装C语言库
lxml XML 解析器 BeautifulSoup(markup, “xml”) 速度快、唯一支持XML的解析器 需要安装C语言库
html5lib BeautifulSoup(markup, “html5lib”) 最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档 速度慢、不依赖外部扩展

② 基本使用

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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, 'lxml')
print(soup.prettify())
print(soup.title.string)

# 说明:
# 在这段代码中,首先使用BeautifulSoup将HTML字符串解析成一个文档树对象soup,然后通过调用prettify()方法对文档树进行格式化,使其更易于阅读。接着使用print语句打印格式化后的HTML内容。
# 接下来,通过soup.title.string可以提取HTML中的标题内容。这行代码的意思是从解析后的文档树对象soup中找到title标签,并获取其文本内容。最后通过print语句打印标题的内容。
# prettify() 是 BeautifulSoup 对象的一个方法,它可以将解析的 HTML 文档树进行缩进和格式化,使其更易于阅读和理解。这对于调试和查看解析结果非常有用。

③ 标签选择器

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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, 'lxml')
print(soup.title)
print(type(soup.title))
print(soup.head)
print(soup.p)

# 说明:
# 这段代码使用 BeautifulSoup 库解析了一个 HTML 字符串,并对解析后的对象进行了一些操作。
# print(soup.title):这行代码打印了解析后文档对象中的 <title> 标签以及其内容。如果存在多个 <title> 标签,该方法只会返回第一个找到的 <title> 标签及其内容。
# print(type(soup.title)):这行代码打印了 soup.title 的数据类型。在这里,soup.title 返回的是一个 BeautifulSoup 的 Tag 对象,因此打印结果应该是 <class 'bs4.element.Tag'>,表示这是一个标签对象。
# print(soup.head):这行代码打印了解析后文档对象中的 <head> 标签以及其内容。和 soup.title 类似,如果存在多个 <head> 标签,该方法只会返回第一个找到的 <head> 标签及其内容。
# print(soup.p):这行代码尝试打印解析后文档对象中的 <p> 标签以及其内容。然而,在 HTML 示例中,并没有 <p> 标签的直接子标签,所以这行代码会打印出 None,表示在当前文档中没有找到符合条件的标签。

获取名称

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.title.name)

获取属性

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.attrs['name'])
print(soup.p['name'])

获取内容

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.string)

嵌套选择

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.head.title.string)

子节点和子孙节点

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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, 'lxml')
print(soup.p.contents)

print(soup.p.children)
for i, child in enumerate(soup.p.children):
    print(i, child)

print(soup.p.descendants)
for i, child in enumerate(soup.p.descendants):
    print(i, child)

# 说明:
# print(soup.p.contents) 这行代码是为了获取 <p> 标签的所有子节点。在这里,<p> 标签有一个文本节点和三个子链接节点(<a> 标签)。.contents 属性可以用于返回一个列表,其中包含了该标签的所有子节点(包括文本节点)。
# print(soup.p.children) 这行代码是为了获取 <p> 标签的所有子节点的迭代器。与 contents 属性不同,.children 属性可以用于返回一个迭代器,其中包含了该标签的所有子节点(同样包括文本节点)。
# enumerate() 函数是 Python 内置函数之一,用于将一个可迭代对象(如列表、元组、字符串等)转换为一个枚举对象,同时返回索引和对应的值。
# soup.p.descendants 这行代码是为了获取 <p> 标签的所有子孙节点的迭代器。.descendants 属性会递归地遍历所有子节点,包括子节点的子节点,以此类推,直到最底层的子节点(叶子节点)。

父节点和祖先节点

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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, 'lxml')
print(soup.a.parent)

print(list(enumerate(soup.a.parents)))

# 说明:
# soup.a.parent 这行代码的作用是获取 <a> 标签的父节点。换句话说,它会返回 <a> 标签的直接父节点(即包含 <a> 标签的标签)。在这个例子中,<a> 标签有一个父节点是 <p> 标签,因为 <a> 标签是 <p> 标签的子节点。
# 如果我们运行 print(soup.a.parent),会输出 <p class="story">...</p>,即 <a> 标签的父节点 <p> 标签的完整内容
#  list(enumerate(soup.a.parents)) 这行代码,我们将 <a> 标签的所有祖先节点取出,并使用 enumerate() 函数给它们编号,最后将它们转换为列表

兄弟节点

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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, 'lxml')
print(list(enumerate(soup.a.next_siblings)))
print(list(enumerate(soup.a.previous_siblings)))

# 说明:
# soup.a.next_siblings 这行代码是为了获取 <a> 标签之后的所有兄弟节点的迭代器。.next_siblings 属性会遍历节点后面的兄弟节点,直到最后一个兄弟节点为止。
# soup.a.previous_siblings 这行代码是为了获取 <a> 标签之前的所有兄弟节点的迭代器。.previous_siblings 属性会遍历节点前面的兄弟节点,直到第一个兄弟节点为止。

④ 标准选择器

find_all( name , attrs , recursive , text , **kwargs )

可根据标签名、属性、内容查找文档
name

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all('ul'))
print(type(soup.find_all('ul')[0]))

for ul in soup.find_all('ul'):
    print(ul.find_all('li'))

# 说明:
# soup.find_all('ul') 这行代码会查找并返回所有 <ul> 标签的列表。在这个例子中,HTML 中包含两个 <ul> 标签,分别是 id 为 "list-1" 和 "list-2" 的列表。
# type(soup.find_all('ul')[0]) 这行代码则是获取第一个 <ul> 标签的类型。由于 find_all() 方法返回的是一个列表,我们通过 [0] 取出第一个 <ul> 标签,然后使用 type() 函数获取其类型。

attrs

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(attrs={
   'id': 'list-1'}))
print(soup.find_all(attrs={
   'name': 'elements'}))

print(soup.find_all(id='list-1'))
print(soup.find_all(class_='element'))

# 说明:
# soup.find_all(attrs={'id': 'list-1'}) 这行代码尝试查找所有具有 id 属性为 "list-1" 的元素。
# soup.find_all(attrs={'name': 'elements'}) 这行代码尝试查找所有具有 name 属性为 "elements" 的元素。然而,在给定的 HTML 中,并不存在具有 name 属性为 "elements" 的元素,因此输出将是一个空列表。
# soup.find_all(id='list-1') 这行代码尝试查找所有具有 id 属性为 "list-1" 的元素。
# soup.find_all(class_='element') 这行代码尝试查找所有具有 class 属性为 "element" 的元素。

text

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(text='Foo'))

# 说明:
# soup.find_all(text='Foo') 这行代码尝试查找文本内容为 "Foo" 的所有元素。在给定的 HTML 中,如果有任何元素的文本内容是 "Foo",那么它们会被返回。如果没有匹配的文本内容为 "Foo" 的元素,则会返回一个空列表。

find( name , attrs , recursive , text , **kwargs )

find返回单个元素,find_all返回所有元素

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find('ul'))
print(type(soup.find('ul')))
print(soup.find('page'))

# 说明:
# soup.find('ul') 这行代码尝试找到第一个 <ul> 标签,并返回该标签及其内容。
# soup.find('page') 这行代码尝试找到名为 'page' 的标签

其他方法

  • find_parents() find_parent()
    • find_parents()返回所有祖先节点,find_parent()返回直接父节点。
  • find_next_siblings() find_next_sibling()
    • find_next_siblings()返回后面所有兄弟节点,find_next_sibling()返回后面第一个兄弟节点。
  • find_previous_siblings() find_previous_sibling()
    • find_previous_siblings()返回前面所有兄弟节点,find_previous_sibling()返回前面第一个兄弟节点。
  • find_all_next() find_next()
    • find_all_next()返回节点后所有符合条件的节点, find_next()返回第一个符合条件的节点
  • find_all_previous() 和 find_previous()
    • find_all_previous()返回节点后所有符合条件的节点, find_previous()返回第一个符合条件的节点

⑤ css选择器

通过select()直接传入CSS选择器即可完成选择

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))

for ul in soup.select('ul'):
    print(ul.select('li'))

# 说明:
# soup.select('.panel .panel-heading') 这行代码使用 CSS 选择器来查找具有类名 "panel" 和 "panel-heading" 的元素。在给定的 HTML 中,只有一个元素符合这个条件,即包含着 "Hello" 文本的 <h4> 标签和其父级元素。因此,返回的结果是包含这个元素的列表。
# soup.select('ul li') 这行代码使用 CSS 选择器来查找所有 <ul> 标签内部的 <li> 元素。在给定的 HTML 中,有两组符合条件的元素,分别是两个 <ul> 内的所有 <li> 元素。因此,返回的结果是包含这些元素的列表。
# soup.select('#list-2 .element') 这行代码使用 CSS 选择器来查找 id 属性为 "list-2" 的 <ul> 标签内部类名为 "element" 的 <li> 元素。在给定的 HTML 中,有两个符合条件的 <li> 元素。因此,返回的结果是包含这些元素的列表。
# print(type(soup.select('ul')[0])) 这行代码打印出了 soup.select('ul')[0] 的返回结果的类型,即返回的元素对象类型。
# 通过使用 Beautiful Soup 库的 select 方法,可以方便地通过 CSS 选择器来选择并返回匹配条件的元素。这对于从 HTML 文档中提取特定元素非常有用。

# 最后一段代码的作用是遍历 Beautiful Soup 对象中所有 <ul> 元素,然后针对每个 <ul> 元素再选择其内部的所有 <li> 元素,并打印输出这些 <li> 元素。

获取属性

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for ul in soup.select('ul'):
    print(ul['id'])
    print(ul.attrs['id'])

获取内容

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for li in soup.select('li'):
    print(li.get_text())

总结:

  • 推荐使用lxml解析库,必要时使用html.parser
  • 标签选择筛选功能弱但是速度快
  • 建议使用find()、find_all()查询匹配单个结果或者多个结果
  • 如果对CSS选择器熟悉建议使用select()
  • 记住常用的获取属性和文本值的方法

4 PyQuery库详解

强大又灵活的网页解析库。如果你觉得正则写起来太麻烦如果你觉得BeautifulSoup语法太难记,如果你熟悉jQuery的语法,那么PyQuery就是你的绝佳选择。

jQuery 是一个流行的 JavaScript 库,旨在简化 JavaScript 在网页中的开发和操作。它提供了强大的 API 和简洁的语法,使得在网页上进行 DOM 操作、事件处理、动画效果等变得更加容易和高效。

PyQuery 是一个用于解析 HTML 文档并提供类似 jQuery 的语法和方法的 Python 库。通过 PyQuery,你可以使用类似于 jQuery 的 CSS 选择器语法来查找、操作和修改 HTML 文档中的元素,从而方便地进行网页数据提取、信息筛选等操作。

PyQuery 的主要功能包括:

  • 使用 CSS 选择器来选择 HTML 元素。
  • 查找、遍历和操作 HTML 元素。
  • 获取元素的属性和文本内容。
  • 支持类似于 jQuery 的链式操作。
  • 可以方便地处理爬取到的网页内容,提取需要的信息。

① 初始化

在用到beautifusoup的时候需要进行初始化设置,例如通过soup = BeautifulSoup(html, 'lxml')来生成一个BeautifulSoup对象,那么pyquery也需要进行初始化操作。

字符串初始化

html = '''
<div>
    <ul>
         <li class="item-0">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1 active"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('li'))

# 说明:
# 使用 pq() 方法创建一个 PyQuery 对象 doc,该对象用于表示 HTML 文档的根元素。
# doc('li') 会通过css选择器li选择所有的 <li> 元素,并返回一个 PyQuery 对象
# 注意:id选择器前面加#,类选择器前面加.,标签选择器什么也不加。

url初始化

from pyquery import PyQuery as pq
doc = pq(url='http://www.baidu.com')
print(doc('head'))

# 说明:
# 这段代码使用 PyQuery 库从指定的 URL 中获取 HTML 文档并进行解析,然后选择文档中的 head 元素,并将结果打印出来

文件初始化

from pyquery import PyQuery as pq
doc = pq(filename='demo.html')
print(doc('li'))

# 说明:
# 跟上面类似,通过filename参数传入要初始化的文件

② 基本CSS选择器

html = '''
<div id="container">
    <ul class="list">
         <li class="item-0">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1 active"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('#container .list li'))

# 说明:
# 这段代码使用了 PyQuery 库来解析 HTML 文档,并选择了 id 为 "container" 的 <div> 元素下 class 为 "list" 的 <ul> 元素下的所有 <li> 元素。
# #.这些符号刚说过,css选择器,从左往右,层级变深。

③ 查找元素

子元素

html = '''
<div id="container">
    <ul class="list">
         <li class="item-0">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1 active"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')
print(type(items))
print(items)
lis = items.find('li')
print(type(lis))
print(lis)

# 说明:
# 这段代码使用 PyQuery 库解析了一个 HTML 文档,并且选择了 class 为 "list" 的元素,并查找其中的所有 <li> 元素。
# items.find('li') 表示在选中的元素中查找所有的 <li> 元素。
# 注意,find() 方法返回的是一个 PyQuery 对象,而不是一个真正的列表。如果您需要将结果转换为列表形式,可以使用 .items() 方法,例如 lis.items()。
lis = items.children()
print(type(lis))
print(lis)

# 说明:
# lis = items.children() 将返回一个 PyQuery 对象,其中包含了所有直接子元素。当直接打印输出 lis 时,您会看到包含所有直接子元素的结果。
lis = items.children('.active')
print(lis)

# 说明:
# children是查找标签子元素,也可以传入选择器,单独找到某些指定的子元素

父元素

html = '''
<div id="container">
    <ul class="list">
         <li class="item-0">first item</li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1 active"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')
container = items.parent()
print(type(container))
print(container)

# 说明:
# 通过 items.parent() 方法获取了 items 的父元素,并将结果存储在变量 container 中。
from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')
parents = items.parents()
print(type(parents))
print(parents)

# 说明:
# 调用了 items.parents() 方法来获取所有祖先元素,并将结果存储在变量 parents 中。 
# 打印所有祖先元素的意思是打印选中元素的所有父级元素,一直往上找到最顶层的那一个元素。也就是说,如果一个元素有多个父级元素,parents() 方法将返回所有的父级元素,以及它们的父级元素,直到 html 的根元素。
parent = items.parents('.wrap')
print(parent)

# 说明:
# 跟上面类似,查找父级元素也可以插入参数,找到某些指定的父级元素

兄弟元素

html = '''
<div class="wrap">
    <div id="container">
        <ul class="list">
             <li class="item-0">first item</li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             <li class="item-1 active"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
         </ul>
     </div>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.list .item-0.active')
print(li.siblings())

# 说明:
# 这段代码使用 PyQuery 库来解析 HTML,并选择具有类名 "item-0 active" 的 li 元素。然后使用 siblings() 方法来获取该元素的所有同级元素。
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.list .item-0.active')
print(li.siblings('.active'))

# 这段代码的功能是选择具有类名 "item-0 active" 的 li 元素,然后使用 siblings('.active') 方法来获取该元素的所有具有类名 "active" 的同级元素。

④ 遍历

单个元素

html = '''
<div class="wrap">
    <div id="container">
        <ul class="list">
             <li class="item-0">first item</li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             <li class="item-1 active"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
         </ul>
     </div>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)

lis = doc('li').items()
print(type(lis))
for li in lis:
    print(li)

# li = doc('.item-0.active')这个代码是获取单个标签
# 当我们使用 doc('li').items() 方法时,会得到一个生成器对象,它可以通过迭代来访问所有匹配的元素。在遍历这个生成器时,每次迭代都会返回 PyQuery 对象,它包含了一个 li 元素及其所有子元素的信息。

⑤ 获取信息

获取属性

html = '''
<div class="wrap">
    <div id="container">
        <ul class="list">
             <li class="item-0">first item</li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             <li class="item-1 active"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
         </ul>
     </div>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active a')
print(a)
print(a.attr('href'))
print(a.attr.href)

# 在 PyQuery 中,获取属性值的方法有两种:1.使用 attr() 方法:a.attr('href') 2.直接通过属性名获取:a.attr.href

获取文本

from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active a')
print(a)
print(a.text())

# 通过 text() 方法获取标签文本内容
# 如果想要获取 <a> 元素内部的文本内容而不包括子元素的内容,可以使用 text() 方法获取文本内容前先使用 contents() 方法过滤出其中的文本节点

获取HTML

from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
print(li.html())

# 通过 html() 方法获取其 HTML 内容并进行打印输出

⑥ DOM操作

addClass、removeClass

html = '''
<div class="wrap">
    <div id="container">
        <ul class="list">
             <li class="item-0">first item</li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             <li class="item-1 active"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
         </ul>
     </div>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.removeClass('active')
print(li)
li.addClass('active')
print(li)

# 通过removeClass删除属性,通过addClass增加属性

attr、css

html = '''
<div class="wrap">
    <div id="container">
        <ul class="list">
             <li class="item-0">first item</li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             <li class="item-1 active"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
         </ul>
     </div>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.attr('name', 'link')
print(li)
li.css('font-size', '14px')
print(li)

# 使用 attr('name', 'link') 方法为该元素添加了一个名为 name、值为 link 的属性。
# 使用 css('font-size', '14px') 方法为该元素设置了 CSS 样式,将字体大小设定为 14px。

remove

html = '''
<div class="wrap">
    Hello, World
    <p>This is a paragraph.</p>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
wrap = doc('.wrap')
print(wrap.text())
wrap.find('p').remove()
print(wrap.text())

其他DOM方法
http://pyquery.readthedocs.io/en/latest/api.html

⑦ 伪类选择器

html = '''
<div class="wrap">
    <div id="container">
        <ul class="list">
             <li class="item-0">first item</li>
             <li class="item-1"><a href="link2.html">second item</a></li>
             <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
             <li class="item-1 active"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
         </ul>
     </div>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('li:first-child')
print(li)
li = doc('li:last-child')
print(li)
li = doc('li:nth-child(2)')
print(li)
li = doc('li:gt(2)')
print(li)
li = doc('li:nth-child(2n)')
print(li)
li = doc('li:contains(second)')
print(li)

# li:first-child:选择第一个 <li> 元素。
# li:last-child:选择最后一个 <li> 元素。
# li:nth-child(2):选择第二个 <li> 元素。
# li:gt(2):选择索引大于 2 的所有 <li> 元素(即除前三个 <li> 元素外的所有 <li> 元素)。
# li:nth-child(2n):选择索引为偶数的所有 <li> 元素。
# li:contains(second):选择包含文本 "second" 的所有 <li> 元素。

官方文档:
http://www.w3school.com.cn/css/index.asp
http://pyquery.readthedocs.io/

5 Selenium库详解

自动化测试工具,支持多种浏览器。爬虫中主要用来解决JavaScript渲染的问题。

它可以模拟用户在浏览器中的交互行为。使用 Selenium,您可以编写 Python 脚本来打开网页、填写表单、点击按钮等操作,并获取页面内容或执行其他操作。

注意:Selenium需要通过浏览器驱动来控制浏览器。因此,在使用Selenium之前,需要下载并安装相应浏览器的驱动,比如ChromeDriver、FirefoxDriver等。

① 基本使用

以下是一个比较全面的selenium例子

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

browser = webdriver.Chrome()
try:
    browser.get('https://www.baidu.com')
    input = browser.find_element_by_id('kw')
    input.send_keys('Python')
    input.send_keys(Keys.ENTER)
    wait = WebDriverWait(browser, 10)
    wait.until(EC.presence_of_element_located((By.ID, 'content_left')))
    print(browser.current_url)
    print(browser.get_cookies())
    print(browser.page_source)
finally:
    browser.close()
    
# 说明:
# 这段代码使用了 Selenium WebDriver 来打开百度首页,搜索关键词 "Python",等待搜索结果加载完成后,获取当前页面的 URL、Cookies 以及页面源码,并最终关闭浏览器。接下来解释一下代码的各个部分:
# from selenium import webdriver:从 Selenium 库中导入 webdriver 模块,用于控制浏览器操作。
# from selenium.webdriver.common.by import By:从 Selenium 的 webdriver 模块中导入 By 类,用于指定元素定位方式。
# from selenium.webdriver.common.keys import Keys:从 Selenium 的 webdriver 模块中导入 Keys 类,用于模拟键盘输入。
# from selenium.webdriver.support import expected_conditions as EC:从 Selenium 的 support 模块中导入 expected_conditions 模块,并重命名为 EC,用于定义等待条件。
# from selenium.webdriver.support.wait import WebDriverWait:从 Selenium 的 support 模块中导入 WebDriverWait 类,用于设置显示等待。
# browser = webdriver.Chrome():创建一个 Chrome 浏览器对象,可以通过该对象控制浏览器的行为。
# browser.get('https://www.baidu.com'):使用浏览器对象打开百度首页。
# input = browser.find_element_by_id('kw'):通过 ID 定位方式找到百度首页搜索输入框元素,并将其赋值给变量 input。
# input.send_keys('Python'):在搜索输入框中输入关键词 "Python"。
# input.send_keys(Keys.ENTER):模拟按下回车键,执行搜索操作。
# wait = WebDriverWait(browser, 10):创建一个 WebDriverWait 对象,设置最大等待时间为 10 秒。
# wait.until(EC.presence_of_element_located((By.ID, 'content_left'))):等待直到搜索结果页面中的内容加载完成,通过检查搜索结果容器的 ID ('content_left') 来确认页面加载完成。
# print(browser.current_url):打印当前页面的 URL。
# print(browser.get_cookies()):打印当前页面的 Cookies。
# print(browser.page_source):打印当前页面的 HTML 源码。
# browser.close():关闭浏览器。

② 声明浏览器对象

from selenium import webdriver

browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()

# 这段代码展示了如何使用不同的浏览器驱动程序来实例化 Selenium WebDriver 对象。每个 webdriver.* 表示一个不同的浏览器驱动程序,

③ 访问页面

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
print(browser.page_source)
browser.close()

# 这段代码使用 Selenium 中的 WebDriver 对象来打开 Chrome 浏览器,访问淘宝网站,并输出页面的 HTML 源码,然后关闭浏览器。

④ 查找元素

单个元素

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element_by_id('q')
input_second = browser.find_element_by_css_selector('#q')
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first, input_second, input_third)
browser.close()

# 这段代码使用 Selenium WebDriver 在打开 Chrome 浏览器并访问淘宝网站后,分别通过不同的方式定位搜索输入框元素,并打印这些元素的信息。
# input_first = browser.find_element_by_id('q'):通过 ID 定位方式找到页面中的搜索输入框元素,并将其赋值给 input_first 变量。
# input_second = browser.find_element_by_css_selector('#q'):通过 CSS 选择器定位方式找到页面中的搜索输入框元素,并将其赋值给 input_second 变量。
# input_third = browser.find_element_by_xpath('//*[@id="q"]'):通过 XPath 定位方式找到页面中的搜索输入框元素,并将其赋值给 input_third 变量。//:表示从当前节点开始,选择匹配模式的任意位置的节点。*:表示选择所有节点。[@id="q"]:表示选择具有id属性为"q"的元素。

一些查找方法:

  • find_element_by_name
  • find_element_by_xpath
  • find_element_by_link_text
  • find_element_by_partial_link_text
  • find_element_by_tag_name
  • find_element_by_class_name
  • find_element_by_css_selector
from selenium import webdriver
from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element(By.ID, 'q')
print(input_first)
browser.close()

# 刚才提到过By是用于指定元素定位方式。
# 通过 By.ID 方法指定使用 ID 定位方式,找到页面中的搜索输入框元素,并将其赋值给 input_first 变量。最后,打印输出 input_first 变量,关闭浏览器
# 需要注意的是,Selenium 中提供了不同的定位方式,如By.ID、By.CSS_SELECTOR、By.XPATH等,用于根据不同的属性定位页面元素。在这段代码中,使用了 By.ID 方法指定了使用 ID 定位方式。

多个元素

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
lis = browser.find_elements_by_css_selector('.service-bd li')
print(lis)
browser.close()
# ----------------------------
from selenium import webdriver
from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
lis = browser.find_elements(By.CSS_SELECTOR, '.service-bd li')
print(lis)
browser.close()

# 获取多个元素的方法跟刚才相比就是element后面多加个s表示复数
# 上面列举的其他查找方法也是类似的

⑤ 元素交互操作

对获取的元素调用交互方法

from selenium import webdriver
import time

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input = browser.find_element_by_id('q')
input.send_keys('iPhone')
time.sleep(1)
input.clear()
input.send_keys('iPad')
button = browser.find_element_by_class_name('btn-search')
button.click()

# 这段代码使用 Selenium 的 WebDriver 来模拟浏览器操作,打开淘宝网站,向搜索框输入关键词 "iPhone",然后清空搜索框内容,重新输入关键词 "iPad",最后点击搜索按钮进行搜索。
# button.click() 点击搜索按钮,触发搜索操作。

更多操作

交互动作

将动作附加到动作链中串行执行

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
target = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()

# 首先创建了一个 Chrome 浏览器的实例,然后打开了一个网页,并切换到了名为 "iframeResult" 的 iframe 中。iframe 是嵌入到网页中的另一个独立的页面,需要切换到该 iframe 才能操作其中的元素。
# from selenium.webdriver import ActionChains:导入 Selenium 的 ActionChains 类,用于执行鼠标操作。
# iframe(内联框架)是 HTML 中的一个标签,用于在网页中嵌入另一个 HTML 页面。通过使用 iframe 标签,我们可以将一个网页嵌入到另一个网页中,并且用户可以在原始页面的某个位置看到嵌入的页面。
# browser.switch_to.frame('iframeResult'):切换到名为 "iframeResult" 的 iframe 中,以便在该 iframe 中进行操作
# source = browser.find_element_by_css_selector('#draggable'):在当前的 iframe 中,使用 CSS 选择器找到 id 为 "draggable" 的源元素。
# target = browser.find_element_by_css_selector('#droppable'):在当前的 iframe 中,使用 CSS 选择器找到 id 为 "droppable" 的目标元素。
# actions = ActionChains(browser):创建一个 ActionChains 对象,用于执行鼠标操作。
# actions.drag_and_drop(source, target):执行拖拽操作,将源元素拖拽到目标元素上。
# actions.perform():执行之前定义的鼠标操作。

⑥ 执行JavaScript

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')

# 这段代码使用 Selenium WebDriver 打开知乎网站,然后执行 JavaScript 代码实现页面滚动和弹出警告框的效果
# browser.execute_script('window.scrollTo(0, document.body.scrollHeight)'):执行 JavaScript 代码,将页面滚动到底部。window.scrollTo(x,y) 方法可以将页面滚动到指定的 x、y 坐标位置,其中 0, document.body.scrollHeight 表示在水平方向不滚动,垂直方向滚动到页面的底部。
# browser.execute_script('alert("To Bottom")'):执行 JavaScript 代码,在页面上弹出一个警告框,显示文本 "To Bottom"。这个警告框会阻止代码继续执行,直到用户关闭它。

⑦ 获取元素信息

获取属性

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo)
print(logo.get_attribute('class'))

# 这段代码的作用是使用 Selenium WebDriver 打开知乎网站的探索页面,找到页面中 id 为 'zh-top-link-logo' 的元素(知乎网站的 Logo),然后打印出该元素对象以及该元素的 class 属性值。

获取文本值

from selenium import webdriver

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.text)

# 在代码中,使用 find_element_by_class_name 方法来查找具有特定类名的元素,并尝试打印该元素的文本内容。但是需要注意的是,find_element_by_class_name 方法用于查找具有指定类名的第一个元素,而不是获取元素的文本内容。
# 如果您想要获取元素的文本内容,可以使用 text 属性或者 get_attribute('textContent') 方法。

获取ID、位置、标签名、大小

from selenium import webdriver

browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)

frame(框架)

import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
print(source)
try:
    logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:
    print('NO LOGO')
browser.switch_to.parent_frame()
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)

# 这段代码的作用是使用 Selenium WebDriver 打开一个网页(http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable),然后切换到该页面中的一个 <iframe> 框架(id 为 'iframeResult'),找到页面中的一个可拖拽元素(id 为 'draggable'),并尝试找到页面中的一个 class 为 'logo' 的元素。
# 如果成功找到 'logo' 元素,则打印该元素及其文本内容;如果未找到 'logo' 元素,则打印 'NO LOGO'。随后,代码会切换回父级 frame,并再次尝试找到 class 为 'logo' 的元素,并打印该元素及其文本内容。
# 整体来说,这段代码主要演示了在使用 Selenium WebDriver 进行网页操作时,如何切换到 iframe 中查找元素,以及处理可能出现的 NoSuchElementException 异常。同时展示了如何获取元素对象以及元素的文本内容。

⑧ 等待

隐式等待

当使用了隐式等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常, 换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0

from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)

# 这段代码使用了 Selenium WebDriver 来打开知乎网站并尝试找到一个 class 为 'zu-top-add-question' 的元素。在这段代码中,implicitly_wait(10) 方法设置了一个隐式等待时间为 10 秒,表示如果在查找元素时未能立即找到,则会等待最多 10 秒,直到元素出现或超时。

显式等待

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

browser = webdriver.Chrome()
browser.get('https://www.taobao.com/')
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
print(input, button)

# 这段代码使用了 Selenium WebDriver 来打开淘宝网站,并使用显示等待来等待页面加载和元素定位。
# 使用显示等待 WebDriverWait(browser, 10) 来设置等待时间为最多 10 秒。这意味着在查找元素时,如果元素未能在 10 秒内出现,将会抛出 TimeoutException 异常。
# 倒数第二三两行代码是使用 Selenium 的 WebDriverWait 来等待页面中的元素加载完成,并返回对应的 WebElement 对象。

# input = wait.until(EC.presence_of_element_located((By.ID, 'q')))解释:
# EC.presence_of_element_located 是一个预定义的条件,表示等待指定的元素在 DOM 树中存在(即元素已经被加载到页面中)。
# (By.ID, 'q') 指定了要查找的元素的定位方式为 ID,并且该元素的 ID 属性的值为 'q'。
# wait.until() 方法会一直等待,直到传入的条件返回一个非 False、非空的值(即找到了符合条件的元素),或者超时时间到达。
# 一旦找到指定的元素(ID 为 'q' 的元素),wait.until() 方法会返回该元素的 WebElement 对象,并将其赋值给变量 input。

# button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))解释:
# EC.element_to_be_clickable 是一个预定义的条件,表示等待指定的元素可被点击(即元素已经加载并且处于可交互状态)。
# (By.CSS_SELECTOR, '.btn-search') 指定了要查找的元素的定位方式为 CSS 选择器,并且该元素的类名为 'btn-search'。
# 同样地,wait.until() 方法会等待,直到找到可点击的元素(类名为 'btn-search' 的元素),并返回该元素的 WebElement 对象,赋值给变量 button。

显示等待是针对某个特定条件等待一段时间,而隐式等待是全局性地等待整个页面加载元素的时间。显示等待更加灵活和精准,可以根据需要设置不同的等待条件和时间;而隐式等待则是简单易用但可能会增加整体执行时间。根据实际需求选择合适的等待方式可以提高测试效率。

expected_conditions是一个模块,其中包含了一些预定义的条件类和方法,用于等待页面元素状态的变化。这些条件可以被用于 WebDriverWait 类中,实现更加可靠的等待操作。
以下是模块中的一些条件:

  • title_is 标题是某内容
  • title_contains 标题包含某内容
  • presence_of_element_located 元素加载出,传入定位元组,如(By.ID, ‘p’)
  • visibility_of_element_located 元素可见,传入定位元组
  • visibility_of 可见,传入元素对象
  • presence_of_all_elements_located 所有元素加载出
  • text_to_be_present_in_element 某个元素文本包含某文字
  • text_to_be_present_in_element_value 某个元素值包含某文字
  • frame_to_be_available_and_switch_to_it frame加载并切换
  • invisibility_of_element_located 元素不可见
  • element_to_be_clickable 元素可点击
  • staleness_of 判断一个元素是否仍在DOM,可判断页面是否已经刷新
  • element_to_be_selected 元素可选择,传元素对象
  • element_located_to_be_selected 元素可选择,传入定位元组
  • element_selection_state_to_be 传入元素对象以及状态,相等返回True,否则返回False
  • element_located_selection_state_to_be 传入定位元组以及状态,相等返回True,否则返回False
  • alert_is_present 是否出现Alert

⑨ 前进后退

import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.python.org/')
browser.back()
time.sleep(1)
browser.forward()
browser.close()

# 使用 back() 方法返回到上一个页面,然后通过 forward() 方法前进到下一个页面。

⑩ cookie

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({
   'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())

# 这段代码使用了 Selenium 和 Chrome 浏览器来访问知乎的探索页面,并对浏览器的 cookie 进行操作。
# 使用 browser.add_cookie() 方法向浏览器中添加了一个名为 "name" 的 cookie,域名为 "www.zhihu.com",值为 "germey"。然后再次调用 browser.get_cookies() 方法获取所有 cookie 并打印输出,可以看到新增的 cookie 信息。
# 最后,使用 browser.delete_all_cookies() 方法删除了浏览器中的所有 cookie,并再次调用 browser.get_cookies() 方法获取所有 cookie 并打印输出,此时应该看不到任何 cookie 信息。

十一 选项卡管理

import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.execute_script('window.open()')
print(browser.window_handles)
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(1)
browser.switch_to_window(browser.window_handles[0])
browser.get('https://python.org')

# 这个例子演示了如何在浏览器中使用 Selenium 控制标签页的切换。
# browser.execute_script('window.open()') 执行了 JavaScript 脚本来新打开一个空白标签页。
# browser.window_handles 返回当前所有标签页的句柄列表,可以通过索引来访问各个标签页。
# browser.switch_to_window(handle) 方法用于切换到指定句柄对应的标签页。
# 需要注意的是,switch_to_window 方法已经被废弃,建议使用 switch_to.window 方法来代替。

# execute_script() 是 Selenium WebDriver 提供的一个方法,用于在浏览器中执行 JavaScript 代码。通过 execute_script() 方法,可以直接在当前页面的上下文中执行自定义的 JavaScript 代码,从而实现一些特定的操作或功能。

十二 异常处理

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.find_element_by_id('hello')

# 页面中并不存在 id 为 'hello' 的元素,那么 browser.find_element_by_id('hello') 将会抛出 NoSuchElementException 异常,因为 Selenium 没有找到匹配的元素。
# 接下来处理一下异常

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException

browser = webdriver.Chrome()
try:
    browser.get('https://www.baidu.com')
except TimeoutException:
    print('Time Out')
try:
    browser.find_element_by_id('hello')
except NoSuchElementException:
    print('No Element')
finally:
    browser.close()

相关推荐

  1. 爬虫02-python爬虫使用详解

    2024-02-22 22:36:03       41 阅读
  2. Python爬虫 pyquery详解

    2024-02-22 22:36:03       28 阅读
  3. 爬虫基本使用(urllib详细解析)

    2024-02-22 22:36:03       27 阅读
  4. 爬虫基本使用(httpx详细解析)

    2024-02-22 22:36:03       29 阅读
  5. python爬虫常用

    2024-02-22 22:36:03       34 阅读
  6. Python爬虫利器:BeautifulSoup详解

    2024-02-22 22:36:03       39 阅读
  7. Python爬虫 Beautiful Soup详解

    2024-02-22 22:36:03       26 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-22 22:36:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-22 22:36:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-22 22:36:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-22 22:36:03       20 阅读

热门阅读

  1. FFmpeg的HEVC解码器源代码学习笔记-2

    2024-02-22 22:36:03       29 阅读
  2. C++面试:SQL注入、web shell攻击的危害和规避方法

    2024-02-22 22:36:03       40 阅读
  3. Spring手动获取bean的四种方式

    2024-02-22 22:36:03       29 阅读
  4. 利用gvim宏快速生成连续带数字下标的信号

    2024-02-22 22:36:03       29 阅读
  5. 三年功能测试,测试工作吐槽

    2024-02-22 22:36:03       21 阅读
  6. 多模态相关论文笔记

    2024-02-22 22:36:03       31 阅读
  7. react实现拖拽的插件

    2024-02-22 22:36:03       33 阅读