Python爬虫基础(一) —— 基本爬虫库的使用

2023-05-16

文章目录

  • 使用urllib库
    • 使用request模块发送请求
      • 1.使用urlopen()
        • urlopen - data参数
        • urlopen - timeout参数
      • 2. Request()
      • 3.高级用法
        • 验证
        • 代理
        • Cookies
    • 使用error模块处理异常
      • 1. URLError
      • 2. HTTPError
    • 使用parse模块解析链接
      • 1. urlparse()
      • 2. urlunparse()
      • 3. urlsplit()
      • 4. urlunsplit()
      • 5. urljoin()
      • 6. urlencode()
      • 7. parse_qs()
      • 8. quote()
      • 9. unquote()
  • 使用requests库
    • 基本用法
    • GET请求
      • 抓取网页
      • 抓取二进制数据 | 图片,视频
      • 响应
    • POST请求
    • 高级用法
      • 1. 文件上传
      • 2. cookie
      • 3.会话维持
      • 4. SSL证书验证
      • 5. 代理设置
      • 6. 超时验证
      • 7. 身份认证
      • 8. Prepared Request
  • 正则表达式
    • 1. match()
      • 提取分组中的内容
      • 贪婪和非贪婪
      • 修饰符
    • 2. search()
    • 3. findall()
      • 4. sub()
      • 5. complie()

使用urllib库

  在Python2中,有urllib和urllib2两个库来实现请求的发送。而在python3中,已经不存在urllib这个库了,统一为urllib。

  首先来了解一下urllib库,它是Python内置的http请求库,所以不需要任何额外安装即可使用。它包含如下四个模块:

  • request:它是最基本的http请求模块,可以用于模拟发送请求。
  • error:异常处理模块,如果出现请求错误,我们可以捕获这些异常。
  • parse:一个工具模块,提供了许多url处理方法,比如拆分,解析,合并等。
  • robotparse:主要用于识别网站的robot.txt文件,然后判断哪些网站可以爬,哪些网站不可以爬。

使用request模块发送请求

1.使用urlopen()

# urlopen()的函数头
urllib.request.urlopen(url, data=None, [ timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
import urllib.request

response = urllib.request.urlopen('https://www.python.org')
# print(response.read().decode('utf-8'))
print(type(response))   # 输出 <class 'http.client.HTTPResponse'>

  可见,response是一个HTTPResponse类型的对象,其主要包括read(),readinto(),getheader(name),getheaders(),fileno()等方法,以及msg,version,reason,debuglevel,closed等属性。

  调用read()方法可以得到目标网址的网页源码,查看status属性可以得到网站返回结果中的状态码。

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))

# /* ------------------- 输出: --------------------*\
# 200
# [
#      ('Server', 'nginx'),
#      ('Content-Type', 'text/html; charset=utf-8'),
#      ('X-Frame-Options', 'SAMEORIGIN'),
#      ('x-xss-protection', '1; mode=block'),
#      ('X-Clacks-Overhead', 'GNU Terry Pratchett'),
#      ('Via', '1.1 varnish'),
#      ('Content-Length', '49066'),
#      ('Accept-Ranges', 'bytes'),
#      ('Date', 'Thu, 17 Jan 2019 06:23:33 GMT'),
#      ('Via', '1.1 varnish'),
#      ('Age', '661'),
#      ('Connection', 'close'),
#      ('X-Served-By', 'cache-iad2134-IAD, cache-tyo19936-TYO'),
#      ('X-Cache', 'MISS, HIT'),
#      ('X-Cache-Hits', '0, 1283'),
#      ('X-Timer', 'S1547706213.363137,VS0,VE0'),
#      ('Vary', 'Cookie'),
#      ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')
#  ]
# nginx

urlopen - data参数

  data 参数是可选的,如果传递了这个参数,则请求方式就变成了POST方式。data参数必须是字节流类型的。

网站httpbin.org能将我们的请求字段再回给我们。

import urllib.request
import urllib.parse

# urlencode()将字典参数转换为字符串,bytes()将字符串转换为字节流
data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post', data=data)
print(response.read())

# /* ------------------- 输出: --------------------*\
# {
#     "args": {},
#     "data": "",
#     "files": {},
#     "form": {
#         "word": "hello"
#     },
#     "headers": {
#         "Accept-Encoding": "identity",
#         "Connection": "close",
#         "Content-Length": "10",
#         "Content-Type": "application/x-www-form-urlencoded",
#         "Host": "httpbin.org",
#         "User-Agent": "Python-urllib/3.5"
#     },
#     "json": null,
#     "origin": "171.42.142.25",
#     "url": "http://httpbin.org/post"
# }

  可见,上述请求中的data数据放在了form字段中,这表明我们现在模拟的是以POST方式传输数据的表单提交方式。

urlopen - timeout参数

  timeout 参数用于设置超时时间,单位为秒。如果请求超出了设置的这个时间,还没有得到响应,那么就会抛出异常。如果不指定此参数,就使用全局默认时间。它支持HTTP , HTTPS 、FTP请求。

import urllib.request

response = urllib.request.urlopen('http://httpbin.org/get', timeout=1)
print(response.read())

# /* ------------------- 输出: --------------------*\

# {
#     "args": {},
#     "headers": {
#         "Accept-Encoding": "identity",
#         "Connection": "close",
#         "Host": "httpbin.org",
#         "User-Agent": "Python-urllib/3.5"
#     },
#     "origin": "171.42.142.25",
#     "url": "http://httpbin.org/get"
# }

由于由于请求超时会抛出异常,因此我们可以对上述代码添加异常排查:

import urllib.request
import urllib.error
import socket

try:
    response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
    # 如果e的error类型(保存在e的reason字段中)为socket.timeout
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')

2. Request()

如果需要在请求头中添加参数,则需要Request()来构建。

import urllib.request

request = urllib.request.Request('https://python.org')
# 此时ulropen()的参数不再是一个网址了,而是一个Request类型的对象
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))

Request的构造方法:

# class urllib.request.Request(url, data=None, headers={}, origin_req_host=None,unverifiable=False,method=None)
# headers:请求头,是一个字典
# origin_req_host:请求方的host名称或IP地址
# unverifiable:表示这个请求是否是无法被验证的,默认False,表明用户没有足够的权限来选择接收这个请求的结果
# method:请求的方法,如GET,POST和PUT等

下面来看一个详细的使用Request()的例子:

from urllib import request, parse

url = 'http://httpbin.org/post'
headers = {
    # 伪装游览器标识,默认的User-Agent是Python-urllib
    'User-Agent': 'Mozilla/4.0(compatible; MSIE 5.5; Windows NT)',
    # 目标主机名
    'Host':'httpbin.org'
}
# data源数据
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'))

# /* ------------------- 输出: --------------------*\

# {
#   "args": {},
#   "data": "",
#   "files": {},
#   "form": {
#     "name": "Germey"
#   },
#   "headers": {
#     "Accept-Encoding": "identity",
#     "Connection": "close",
#     "Content-Length": "11",
#     "Content-Type": "application/x-www-form-urlencoded",
#     "Host": "httpbin.org",
#     "User-Agent": "Mozilla/4.0(compatible; MSIE 5.5; Windows NT)"
#   },
#   "json": null,
#   "origin": "171.42.142.25",
#   "url": "http://httpbin.org/post"
# }

另外,请求头除了可以直接定义外,还可以使用req的add_header()方法:

req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0(compatible; MSIE 5.5; Windows NT)')
req.add_header('Host','httpbin.org')

3.高级用法

  在上面的使用中,虽然可以构造请求,但是对于一些更高级的操作(比如Cookies 处理、代理设置等),就需要更强大的工具Handler登场了。简而言之,我们可以把它理解为各种处理器,有专门处理登录验证的,有处理Cookies的,有处理代理设置的。利用它们,我们几乎可以做到HTTP请求中所有的事情。

  首先,介绍一下urllib.request模块中的BaseHandler类,它是所有其他Handler的父类,它提供了最基本的方法,例如default_open()、protocol_request()等。

再来看看BaseHandleer的子类:

  • HTTPDefaultErrorHandler:用于处理HTTP 响应错误,错误都会抛出HTTP Error 类型的异常。
  • HTTPRedirectHandler:用于处理重定向。
  • HTTPCookieProcessor: 用于处理Cookies 。
  • ProxyHandler:用于设置代理,默认代理为空。
  • HπPPasswordMgr:用于管理密码,它维护了用户名和密码的表。
  • HTTPBasicAuthHandler:用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题。

  另外一个比较重要的类就是OpenerDirector,我们可以称之为Opener,之前用过的urlopen()实际上也属于Opener,它是一个urllib提供给我们的封装好了的Opener。

  那么,为什么要引人Opener呢?因为需要实现更高级的功能。之前使用的Request和urlopen()相当于类库为你封装好了极其常用的请求方法,利用它们可以完成基本的请求,但是现在不一样了,我们需要实现更高级的功能,所以需要深入一层进行配置,使用更底层的实例来完成操作,所以这里就用到了Opener 。

  使用Opener需要用到open()方法,返回的类型和urlopen()如出一辙,那么,它和Handler 有什么关系呢?简而言之,就是利用Handler来构建Opener 。

验证

对于需要账户验证才能登陆查看网页来说,需要使用Handler构建opener来进行模拟验证。

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError

username = '程一夕'
password = '#importali'
url = 'https://account.aliyun.com/login/login.htm?oauth_callback=http%3A%2F%2Fdns.console.aliyun.com%2F#/dns/setting/baibainote.pro'

p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
# 实例化HTTPBasicAuthHandler对象,其参数是HTTPPasswordMgrWithDefaultRealm对象
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)

try:
    result = opener.open(url)
    html = result.read().decode('utf-8')
    result = opener.open(url)
    print(html)
except URLError as e:
    print(e.reason)

代理

from urllib.error import URLError
from urllib.request import  ProxyHandler, build_opener

proxy_handler = ProxyHandler({
    'http': '127.0.0.1:12308'
})

opener = build_opener(proxy_handler)
try:
    response = opener.open('https://www.baidu.com')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

Cookies

可通过下面的方式来获取一个网站的cookie:

import http.cookiejar, urllib.request

cookie = http.cookiejar.CookieJar()
# 使用HTTPCookieProcessor来构建handler
handler = urllib.request.HTTPCookieProcessor(cookie)
# 利用生成的handler来构建opener
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
    print(item.name + "=" + item.value)

上述输出:

BAIDUID=D450CE81692242D57AF5680E33E6F545:FG=1
BIDUPSID=D450CE81692242D57AF5680E33E6F545
H_PS_PSSID=1423_21104_28328_28131_28267_22073
PSTM=1547712883
delPer=0
BDSVRTM=0
BD_HOME=0

将cookie保存为Mozila的文件形式,可以使用如下代码:

import http.cookiejar, urllib.request

# 将cookie保存为Mozila游览器的cookie格式
cookie = http.cookiejar.MozillaCookieJar('cookies.txt')
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)

这里的cookies.txt文件内容为:

# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file!  Do not edit.

.baidu.com	TRUE	/	FALSE	3695196365	BAIDUID	3941F31A3424DAB2A92D7F2AA1696281:FG=1
.baidu.com	TRUE	/	FALSE	3695196365	BIDUPSID	3941F31A3424DAB2A92D7F2AA1696281
.baidu.com	TRUE	/	FALSE		H_PS_PSSID	1454_21093_28329_28131_28267
.baidu.com	TRUE	/	FALSE	3695196365	PSTM	1547712718
.baidu.com	TRUE	/	FALSE		delPer	0
www.baidu.com	FALSE	/	FALSE		BDSVRTM	0
www.baidu.com	FALSE	/	FALSE		BD_HOME	0

当然了,也可以改为LWP格式的cookie:

cookie = http.cookiejar.LWPCookieJar('cookies.txt')

此时,cookies.txt文件的内容就变为:

#LWP-Cookies-2.0
Set-Cookie3: BAIDUID="DC98555BA602B4179B60D70967807CE0:FG=1"; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-02-04 11:34:32Z"; version=0
Set-Cookie3: BIDUPSID=DC98555BA602B4179B60D70967807CE0; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-02-04 11:34:32Z"; version=0
Set-Cookie3: H_PS_PSSID=1442_21125_18559_28329_28132_28267; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: PSTM=1547713226; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-02-04 11:34:32Z"; version=0
Set-Cookie3: delPer=0; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: BDSVRTM=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
Set-Cookie3: BD_HOME=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0

得到了LWP格式的cookie后,我们就可以从cookies.txt文件中读内容:

import http.cookiejar, urllib.request

cookie = http.cookiejar.LWPCookieJar()
cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))

上述代码运行正常的话,则会输出百度首页的源码。

使用error模块处理异常

1. URLError

  URLError 类来自urllib库的error 模块,它继承自OSError类,是error 异常模块的基类,由request模块产生的异常都可以通过捕获这个类来处理。

from urllib import request, error

try:
    response = request.urlopen('https://www.baidu.com')
except error.URLError as e:
    print(e.reason)

2. HTTPError

  它是URLError的子类,专门用来处理HTTP请求错误,比如认证请求失败等。它有如下3 个属性:

  • code: 返回HTTP 状态码,比如404 表示网页不存在, 500 表示服务器内部错误等。
  • reason: 同父类一样,用于返回错误的原因。
  • headers: 返回请求头
from urllib import request, error

try:
    response = request.urlopen('https://cuiqingcai.com/index.html')
except error.HTTPError as e:
    print(e.reason, e.headers)

# /* ------------------- 输出: --------------------*\
# Not Found 
# # Server: nginx/1.10.3 (Ubuntu)
# # Date: Thu, 17 Jan 2019 11:44:26 GMT
# # Content-Type: text/html; charset=UTF-8
# # Transfer-Encoding: chunked
# # Connection: close
# # Vary: Cookie
# # Expires: Wed, 11 Jan 1984 05:00:00 GMT
# # Cache-Control: no-cache, must-revalidate, max-age=0
# # Link: <https://cuiqingcai.com/wp-json/>; rel="https://api.w.org/"

由于HTTPError是URLError的子类,于是可以先捕获子类的异常再捕获父类的异常:

from urllib import request, error

try:
    response = request.urlopen('https://cuiqingcai.com/index.html')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers)
except error.URLError as e:
    print(e.reason)
else:
    print('Request.successfully')

使用parse模块解析链接

  urllib 库里还提供了parse模块,它定义了URL处理的标准接口,例如实现URL 各部分的抽取、合并以及链接转换。它支持如下协议的URL 处理:file 、ftp 、gopher等。

1. urlparse()

urlparse()定义:

urlparse(urlstring, scheme, allow_fragments)
# urlstring: 待解析的URL字符串
# scheme: 默认协议,如果urlstring中没有包含协议信息,则urlparse的结果中scheme字段的值记为该默认值
# allow_fragments: 是否忽略fragment。如果设为False,则fragment部分会被忽略,它会被解析为path,params或者query的一部分
from urllib.parse import urlparse

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

# /* ------------------- 输出: --------------------*\
# <class 'urllib.parse.ParseResult'>
#    ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='coment')

标准URL格式:scheme://netloc/path;params?query#fragment

  • scheme:协议(😕/前面)
  • netloc:域名(第一个/符号前面)
  • path:访问路径(域名后面)
  • params:参数
  • query:查询条件(?问号后面,一般用作GET类型的URL)
  • fragment:锚点(#号后面)

2. urlunparse()

  有了urlparse(),相应地就有了它的对立方法urlunparse()。它接受的参数是一个可迭代对象,但是它的长度必须是6,否则会抛出参数数量不足或者过多的异常。

from urllib.parse import urlunparse

data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
# urlunparse()的参数可以是列表,元组或其他类型
print(urlunparse(data))

# /* ------------------- 输出: --------------------*\
# http://www.baidu.com/index.html;user?a=6#comment

3. urlsplit()

from urllib.parse import urlsplit

result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment')
print(result)
# SplitResult()是一个元组类型,既可以用属性获取值,也可以使用数字下标
print(result.scheme)
print(result[0])

# /* ------------------- 输出: --------------------*\
# SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment')
# http
# http

4. urlunsplit()

  与urlunparse()类似,它也是将链接各个部分组合成完整链接的方法,传人的参数也是一个可迭代对象,例如列表、元组等,唯一的区别是长度必须为5 。

from urllib.parse import urlunsplit

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

# /* ------------------- 输出: --------------------*\
# http://www.baidu.com/index.html?a=6#comment

5. urljoin()

  有了urlunparse()和urlunsplit()方法,我们可以完成链接的合井,不过前提是必须要有特定长度的对象,且链接的每一部分都要清晰分开。

  此外,我们还有另一个便捷的方法,那就是urljoin()方法。我们可以提供一个base_url 作为第一个参数,将新的链接作为第二个参数,该方法会分析base_url中的scheme 、netloc 和path这3个内容并对新链接缺失的部分进行补充,最后返回结果。

from urllib.parse import urljoin

print(urljoin('http://www.baidu.com', 'FAQ.html'))
print(urljoin('http://www.baidu.com ', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about. html', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://cuiqingcai.com/index.php'))
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'))

# /* ------------------- 输出: --------------------*\
# http://www.baidu.com/FAQ.html
# https://cuiqingcai.com/FAQ.html
# https://cuiqingcai.com/FAQ.html
# https://cuiqingcai.com/FAQ.html?question=2
# https://cuiqingcai.com/index.php
# http://www.baidu.com?category=2#comment
# www.baidu.com?category=2#comment
# www.baidu.com?category=2

  可以发现,base_url提供了三项内容scheme,netloc和path。如果这3项在新的链接里不存在,就予以补充;如果新的链接存在,就使用新的链接的部分。而base_url中的params、query和fragment就不起作用了。

6. urlencode()

from urllib.parse import urlencode

params = {
    'name': 'germey',
    'age': 22
}
base_url = 'http://www.baidu.com'
# urlencode()可将字典类型转化为GET方法的请求参数
url = base_url + urlencode(params)
print(url)

# /* ------------------- 输出: --------------------*\
# http://www.baidu.comname=germey&age=22

7. parse_qs()

  有了序列化,必然就有反序列化。如果我们有一串GET请求参数,利用parse_qs()方法,就可以将它转回字典。

from urllib.parse import parse_qs

query = 'name=germey&age=22'
print(parse_qs(query))

# /* ------------------- 输出: --------------------*\
# {'name': ['germey'], 'age': ['22']}

8. quote()

  该方法可以将内容转化为URL编码的格式。URL中带有中文参数时,有时可能会导致乱码的问题,此时用这个方法可以将中文字符转化为URL编码。

from urllib.parse import quote

keyword = '壁纸'
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)

# /* ------------------- 输出: --------------------*\
# https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8

9. unquote()

有了quote()方法,反之当然就有unquote()方法,它可以进行URL解码:

from urllib.parse import unquote

url = 'https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8'
print(unquote(url))

# /* ------------------- 输出: --------------------*\
# https://www.baidu.com/s?wd=壁纸

使用requests库

  虽然urllib库似乎无所不能,但其中确实有不方便的地方,比如处理网页验证和Cookies时,需要写Opener和Handler来处理,很显然,这两者的构建有点麻烦。为了更加方便地实现这些操作,就需要用到更为强大的库requests,有了它Cookies、登录验证和代理设置等操作都变得额外简单。

基本用法

import requests

# requests库的get方法与urllib库的urlopen()类似
req = requests.get('https://www.baidu.com')
print(type(req))    # Response对象
print(req.status_code)
print(type(req.text))
# print(req.text)   # 目标网址的网页源码【响应体】
print(req.cookies)

# /* ------------------- 输出: --------------------*\
# <class 'requests.models.Response'>
# 200
# <class 'str'>
# <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>

  requests库的get()方法可以完成一个GET请求,但更令人激动的是,其它请求类型在requests中依然只需要一句话来完成:

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

GET请求

要想在GET请求中附加其它参数,也可以用字典类型来构建:

import requests

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

# /* ------------------- 输出: --------------------*\
# {
#   "args": {
#     "age": "22",
#     "name": "germey"
#   },
#   "headers": {
#     "Accept": "*/*",
#     "Accept-Encoding": "gzip, deflate",
#     "Connection": "close",
#     "Host": "httpbin.org",
#     "User-Agent": "python-requests/2.21.0"
#   },
#   "origin": "171.42.142.25",
#   "url": "http://httpbin.org/get?name=germey&age=22"
# }

抓取网页

我们试着抓取一个真正的网页,注意要改游览器标识,否则知乎会禁止抓取。

import requests
import re

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
r = requests.get('https://www.zhihu.com/explore', headers=headers)
# 使用正则表达式匹配内容
pattern = re.compile('explore-feed.*?question_link.*?>(.*?)</a>', re.S)
titles = re.findall(pattern, r.text)
print(titles)

抓取二进制数据 | 图片,视频

  上面我们爬取的都是文本格式的数据(网页源码),但实际网页上其实有很多图片,视频,音乐等,要想抓取它们,就必须拿到它们的二进制数据。

import requests

r = requests.get('https://github.com/favicon.ico')
# print(r.text)     # 以文本格式表示的二进制数据(乱码)
# print(r.content)  # 图片的二进制bytes数据
# 向文件favicon.ico中写入r.content,即保存二进制数据为图片
with open('favicon.ico', 'wb') as f:
    f.write(r.content)

响应

  发送请求后,得到的自然就是响应。在上面的实例中,我们使用text和content 获取了响应的内容。此外,还有很多属性和方法可以用来获取响应中的其他信息,比如状态码、响应头、Cookies 等。

import requests

r = requests.get('https://www.jianshu.com')
print(type(r.status_code), r.status_code)
print(type(r.headers), r.headers)   # 响应头
print(type(r.cookies), r.cookies)
print(type(r.url), r.url)
print(type(r.history), r.history)   # 请求历史

# /* ------------------- 输出: --------------------*\
# <class 'int'> 403
# <class 'requests.structures.CaseInsensitiveDict'> {'Connection': 'keep-alive', 'Transfer-Encoding': 'chunked', 'Content-Type': 'text/html', 'X-Via': '1.1 PSzjwzdx11at80:10 (Cdn Cache Server V2.0), 1.1 PShbxgdx6gr28:12 (Cdn Cache Server V2.0)', 'Date': 'Thu, 17 Jan 2019 13:44:06 GMT', 'Content-Encoding': 'gzip', 'Server': 'Tengine', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload'}
# <class 'requests.cookies.RequestsCookieJar'> <RequestsCookieJar[]>
# <class 'str'> https://www.jianshu.com/
# <class 'list'> []

  状态码一般用于判断请求是否发送成功。为了更方便的使用状态码,requests库中封装了一个内置的查询对象requests.codes。

import requests

r = requests.get('https://www.jianshu.com')
# ok状态码的值是200
exit() if not r.status_code == requests.codes.ok else print('Request Successfully')

POST请求

import requests

# POST表单请求要加data
data = {'name': 'germey', 'age': 22}
r = requests.post("http://httpbin.org/post", data=data)
print(r.text)

# /* ------------------- 输出: --------------------*\
# {
#   "args": {},
#   "data": "",
#   "files": {},
#   "form": {
#     "age": "22",
#     "name": "germey"
#   },
#   "headers": {
#     "Accept": "*/*",
#     "Accept-Encoding": "gzip, deflate",
#     "Connection": "close",
#     "Content-Length": "18",
#     "Content-Type": "application/x-www-form-urlencoded",
#     "Host": "httpbin.org",
#     "User-Agent": "python-requests/2.21.0"
#   },
#   "json": null,
#   "origin": "171.42.142.25",
#   "url": "http://httpbin.org/post"
# }

高级用法

1. 文件上传

import requests

# 将先前得到的favicon.icon上传
files = {'file': open('favicon.ico', 'rb')}
# 这次POST请求的参数不再是文本形式的data了,而是file
r = requests.post("http://httpbin.org/post", files=files)
print(r.text)

import requests

# 将先前得到的favicon.icon上传
files = {'file': open('favicon.ico', 'rb')}
# 这次POST请求的参数不再是文本形式的data了,而是file
r = requests.post("http://httpbin.org/post", files=files)
print(r.text)

# /* ------------------- 输出: --------------------*\
# {
#   "args": {},
#   "data": "",
#   "files": {
#     "file": "data:application/octet-stream;base64,AAABAAIAEBAAAAEAIAAoBQAAJgAAACAgAAABACAAKBQAAE4FAAAoAAAAEAAAACAAAAABACAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABERE3YTExPFDg4OEgAAAAAAAAAADw8PERERFLETExNpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFJYTExT8ExMU7QAAABkAAAAAAAAAAAAAABgVFRf/FRUX/xERE4UAAAAAAAAAAAAAAAAAAAAAAAAAABEREsETExTuERERHhAQEBAAAAAAAAAAAAAAAAAAAAANExMU9RUVF/8VFRf/EREUrwAAAAAAAAAAAAAAABQUFJkVFRf/BgYRLA4ODlwPDw/BDw8PIgAAAAAAAAAADw8PNBAQEP8VFRf/FRUX/xUVF/8UFBSPAAAAABAQEDAPDQ//AAAA+QEBAe0CAgL/AgIC9g4ODjgAAAAAAAAAAAgICEACAgLrFRUX/xUVF/8VFRf/FRUX/xERES0UFBWcFBQV/wEBAfwPDxH7DQ0ROwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0NEjoTExTnFRUX/xUVF/8SEhKaExMT2RUVF/8VFRf/ExMTTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERERTBUVF/8VFRf/ExMT2hMTFPYVFRf/FBQU8AAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITExTxFRUX/xMTFPYTExT3FRUX/xQUFOEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQU4RUVF/8TExT3FBQU3hUVF/8TExT5Dw8PIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQHxMTFPgVFRf/FBQU3hERFKIVFRf/FRUX/w8PDzQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEEAVFRf/FRUX/xERFKIODg44FRUX/xUVF/8SEhKYAAAAAAAAAAwAAAAKAAAAAAAAAAAAAAAMAAAAAQAAAAASEhKYFRUX/xUVF/8ODg44AAAAABERFKQVFRf/ERESwQ4ODjYAAACBDQ0N3BISFNgSEhTYExMU9wAAAHQFBQU3ERESwRUVF/8RERSkAAAAAAAAAAAAAAADExMTxhUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8TExPGAAAAAwAAAAAAAAAAAAAAAAAAAAMRERSiFRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8RERSiAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQED4TExOXExMT2RISFPISEhTyExMT2RMTE5cQEBA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAIAAAAEAAAAABACAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUVKwweHh4RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbGxscJCQkDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWHSMXFxiSFRUX8RYWF/NAQEAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWGO0WFhfzFhYYlRwcHCUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQkJAcWFhiAFhYY+BUVF/8VFRf/FRUX/yAgIAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRUX/hUVF/8VFRf/FhYY+RYWGIIgICAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbGxscFhYX0BUVF/8VFRf/FRUX/xUVF/8VFRf/KysrBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVFRf9FRUX/xUVF/8VFRf/FRUX/xYWF9IaGhoeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhYbLxUVF+YVFRf/FRUX/BYWGLgWFhh0FhYZZxYWGH5VVVUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUVF/wVFRf/FRUX/xUVF/8VFRf/FRUX/xUVF+YWFhsvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaGh0VFRfmFRUX/xUVF/wYGBhJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRUX+xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF+YaGhodAAAAAAAAAAAAAAAAAAAAAAAAAAAkJCQHFhYX0RUVF/8VFRf/FRUYnQAAAAAVFSAYFhYYcxUVF5AXFxlmJCQkBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwcHBIVFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xYWF9EkJCQHAAAAAAAAAAAAAAAAAAAAABYWGIEVFRf/FRUX/xUVF/EbGxscHBwcJRYWGOsVFRf/FRUX/xUVF/8XFxpOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBgYQBUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xYWGIAAAAAAAAAAAAAAAAAVFRwkFhYY+RUVF/8VFRjuFhYaRRUVKwwWFhfPFRUX/xUVF/8VFRf/FRUX/xYWF8SAgIACAAAAAAAAAAAAAAAAAAAAAAAAAAAVFRi/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FhYY+BYWHSMAAAAAAAAAABYWGJQVFRf/FRUX/xYWF44XFxpaFhYX0RUVF/8VFRf/FRUY4hYWGIAWFhpFHBwcEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIiIg8XFxdCFxcZexYWF9sVFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FxcYkwAAAAAnJycNFRUX8hUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/hYWGIIzMzMFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAAhYWGHQVFRf8FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRfyFRUrDBYWGVIVFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8WFhh0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUVGGAVFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8WFhlSFRUZkRUVF/8VFRf/FRUX/xUVF/8VFRf/FRUYyv///wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWGLcVFRf/FRUX/xUVF/8VFRf/FRUX/xUVGZEWFhjJFRUX/xUVF/8VFRf/FRUX/xUVF/8WFhlcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhYZRxUVF/8VFRf/FRUX/xUVF/8VFRf/FhYYyBYWGOEVFRf/FRUX/xUVF/8VFRf/FRUX/xcXFxYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAIFhYY+BUVF/8VFRf/FRUX/xUVF/8WFhjgFhYY9RUVF/8VFRf/FRUX/xUVF/8VFRfyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFhjeFRUX/xUVF/8VFRf/FRUX/xYWGPUWFhfzFRUX/xUVF/8VFRf/FRUX/xYWGN4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUVGMoVFRf/FRUX/xUVF/8VFRf/FhYX8xUVGNkVFRf/FRUX/xUVF/8VFRf/FhYY9P///wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhYY4RUVF/8VFRf/FRUX/xUVF/8VFRjZFRUYvxUVF/8VFRf/FRUX/xUVF/8VFRf/HBwcJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgIBAVFRf/FRUX/xUVF/8VFRf/FRUX/xUVGL8WFhiVFRUX/xUVF/8VFRf/FRUX/xUVF/8WFhh2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRUYYRUVF/8VFRf/FRUX/xUVF/8VFRf/FhYYlRYWGUcVFRf/FRUX/xUVF/8VFRf/FRUX/xYWGPQZGRkfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsbGxMWFhjrFRUX/xUVF/8VFRf/FRUX/xUVF/8WFhlHKysrBhUVF/EVFRf/FRUX/xUVF/8VFRf/FRUX/xYWGV0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBgYSRUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX8SsrKwYAAAAAFhYYlxUVF/8VFRf/FRUX/xUVF/8VFRf/GRkZMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaGhoeFRUX/xUVF/8VFRf/FRUX/xUVF/8WFhiXAAAAAAAAAAAVFSAYFhYY9BUVF/8VFRf/FRUX/xUVF/8YGBg1AAAAAAAAAAAAAAAAFRUrDBgYGCqAgIACAAAAAAAAAAAAAAAAAAAAAP///wEbGxsmHh4eEQAAAAAAAAAAAAAAABcXFyEVFRf/FRUX/xUVF/8VFRf/FhYY9BUVIBgAAAAAAAAAAAAAAAAWFhiCFRUX/xUVF/8VFRf/FRUX/xcXGWYAAAAAQEBABBcXF2IWFhfnFRUX/xYWF/MWFhfSFRUYwRUVGMAWFhfRFRUX8BUVF/8WFhjtFRUYbCsrKwYAAAAAFhYZUhUVF/8VFRf/FRUX/xUVF/8WFhiCAAAAAAAAAAAAAAAAAAAAACQkJAcWFhjIFRUX/xUVF/8VFRf/FRUY1hUVGKgWFhjsFRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX7xUVGKoVFRjNFRUX/xUVF/8VFRf/FhYYyCQkJAcAAAAAAAAAAAAAAAAAAAAAAAAAABUVIBgVFRjjFRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVGOMVFSAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWHC4VFRjjFRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRjjFhYcLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUVIBgWFhjIFRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FhYYyBUVIBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQkJAcWFhiCFhYY9BUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FhYY9BYWGIIkJCQHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVFSAYFhYYlxUVF/EVFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX/xUVF/8VFRf/FRUX8RYWGJcVFSAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKysrBhYWGUcWFhiVFRUYvxUVGNkWFhfzFhYX8xUVGNkVFRi/FhYYlRYWGUcrKysGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
#   },
#   "form": {},
#   "headers": {
#     "Accept": "*/*",
#     "Accept-Encoding": "gzip, deflate",
#     "Connection": "close",
#     "Content-Length": "6665",
#     "Content-Type": "multipart/form-data; boundary=bdb66546fe28cb2ae0582c9351c7c073",
#     "Host": "httpbin.org",
#     "User-Agent": "python-requests/2.21.0"
#   },
#   "json": null,
#   "origin": "171.42.142.25",
#   "url": "http://httpbin.org/post"
# }

2. cookie

  前面说的urllib库也可以处理cookie,但相对比较复杂,而有了requests,获取和设置Cookies 只需一步即可完成。

import requests

r = requests.get('https://www.baidu.com')
print(r.cookies)    # RequestsCookieJar类型,这是一个Requests库封装的类
for key, value in r.cookies.items():
    print(key + '=' + value)
    
# /* ------------------- 输出: --------------------*\
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
BDORZ=27315

3.会话维持

  在requests中,如果直接利用get()或post()等方法的确可以做到模拟网页的请求,但是这实际上是相当于不同的会话,也就是说相当于你用了两个浏览器打开了不同的页面。

  设想这样一个场景,第一次请求利用post()方法登录了某个网站,第二次想获取成功登录后的自己的个人信息,你又用了一次get()方法去请求个人信息页面。实际上,这相当于打开了两个浏览器,这是两个完全不相关的会话,这样其实是不能获取到个人信息的。

  当然,如果在两次请求时设置一样的cookies也的确可以做到维持会话的效果,但这显得略微繁琐。我们可以引入另一个利器——Session对象。

先看看连续发生两次GET请求能否获取cookie:

import requests

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

# /* ------------------- 输出: --------------------*\
# {
#   "cookies": {}
# }

再使用Session对象试试:

import requests

# 使用同一个Session对象发送的GET请求就维持在同一个会话中
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)

# /* ------------------- 输出: --------------------*\
# {
#   "cookies": {
#     "number": "123456789"
#   }
# }

4. SSL证书验证

  requests 还提供了证书验证的功能。当发送HTTP 请求的时候,它会检查SSL 证书,我们可以使用verify参数控制是否检查此证书。其实如果不加verify参数的话,默认是True ,会自动验证。

import requests

response = requests.get('https://www.12306.cn', verify=False)
print(response.status_code)

  如果请求一个HTTPS 站点,但是证书验证错误时,就会报错,把verify 参数设置为False可以跳过SSL证书验证,避免产生这样的错误。

5. 代理设置

  对于某些网站,在测试的时候请求几次,能正常获取内容。但是一旦开始大规模爬取,对于大规模且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面, 更甚者可能会直接封禁客户端的IP,导致一定时间段内无法访问。这可以通过设置代理来解决。

import requests

proxies = {
    "http": "http://127.0.0.1:12308"    # ,"https": "https://127.0.0.1:12308"
}
r = requests.get('https://www.taobao.com', proxies=proxies)
print(r.text)

6. 超时验证

  在本机网络状况不好或者服务器网络响应太慢甚至无响应时,我们可能会等待特别久的时间才可能收到响应,甚至到最后收不到响应而报错。为了防止服务器不能及时响应,应该设置一个超时时间,即超过了这个时间还没有得到响应,那就报错。这需要用到timeout 参数。这个时间的计算是发送请求到服务器返回响应的时间。

import requests

# 实际上,请求分为两个阶段,即连接(connect)和读取(read),下面设置的timeout表示这两者所耗费的时间总和
# r = requests.get('https://www.taobao.com', timeout=1)
# 可以给timeout传入一个元组分别设置这两个阶段的超时限制
r = requests.get('https://www.taobao.com', timeout=(10, 5))
# timeout默认值为None,表示无限制
print(r.status_code)

7. 身份认证

  如果网站需要登录验证用户身份才能获取到相应网页,这就需要使用requests.auth模块提供的身份认证功能。

import requests
from requests.auth import HTTPBasicAuth

username = '程一夕'
password = '#importali'
url = 'https://account.aliyun.com/login/login.htm?oauth_callback=http%3A%2F%2Fdns.console.aliyun.com%2F#/dns/setting/baibainote.pro'
r = requests.get(url, auth=HTTPBasicAuth('username', 'password'))
# 参数auth可以不用直接传HTTPBasicAuth类型的值,requests.auth模块允许给auth参数传入一个元组,这个元组会默认转换为HTTPBasicAuth类型的值,即:
# r = requests.get(url, 'username', 'password')
print(r.status_code)
print(r.text)

8. Prepared Request

  前面我们使用urllib库时用到了一个request对象来将要发送的请求信息,请求头等封装在一起,这在requests库中叫做Prepared Request,即将要发送的请求信息包。

from requests import Request, Session

url = 'http://httpbin.org/post'
data = {
    'name': 'Germay'
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
s = Session()
# 使用Request()对象封装请求信息
req = Request('POST', url, data=data, headers=headers)
# 将封装好的包放进s的预发请求栏里
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)

# /* ------------------- 输出: --------------------*\
# {
#   "args": {},
#   "data": "",
#   "files": {},
#   "form": {
#     "name": "Germay"
#   },
#   "headers": {
#     "Accept": "*/*",
#     "Accept-Encoding": "gzip, deflate",
#     "Connection": "close",
#     "Content-Length": "11",
#     "Content-Type": "application/x-www-form-urlencoded",
#     "Host": "httpbin.org",
#     "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
#   },
#   "json": null,
#   "origin": "171.42.142.25",
#   "url": "http://httpbin.org/post"
# }

正则表达式

  正则表达式不是Python 独有的,它也可以用在其他编程语言中。但是Python 的re 库提供了对整个正则表达式的实现,利用这个库,可以在Python中使用正则表达式。在Python 中写正则表达式几乎都要用到这个库,

1. match()

import re

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))     # 字符串的长度,即所包含的字符个数
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}', content)
print(result)
print(result.group())   # 目标字符串中得到匹配的子串,即匹配结果
print(result.span())    # 目标字符串中得到匹配的子串在源字符串中的索引区间

# /* ------------------- 输出: --------------------*\
# 41
# <_sre.SRE_Match object; span=(0, 25), match='Hello 123 4567 World_This'>
# Hello 123 4567 World_This
# (0, 25)

提取分组中的内容

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld', content)
print(result)
print(result.group())   # 获得匹配的全部结果
print(result.group(1))  # 提取第一个括号分组中的值
print(result.span())

# /* ------------------- 输出: --------------------*\

# <_sre.SRE_Match object; span=(0, 19), match='Hello 1234567 World'>
# Hello 1234567 World
# 1234567
# (0, 19)

贪婪和非贪婪

import re

# .表示任意字符,*表示前面的字符允许出现任意次,.*组合可以匹配到任意字符
content = 'Hello 1234567 World_This is a Regex Demo'
# ^表示字符串头部,$表示字符串尾部,一头一尾
result = re.match('^He.*(\d+).*Demo$', content)
print(result)
print(result.group(1))

# /* ------------------- 输出: --------------------*\
# <_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
# 7

  上述取出分组结果时,我们可以看到,本来我们的期望是匹配1234567这几个数字的,但匹配结果却显示只有7这一个数字,这就是贪婪模式的效果(默认)。

  也就是说,(\d+)前面的.*将前面6个数字匹配完了(尽可能多的匹配),这6个数字其实并没有进入分组内。

import re

# .表示任意字符(除换行符之外),*表示前面的字符允许出现任意次,.*组合可以匹配到任意字符
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$', content)
print(result)
print(result.group(1))

# /* ------------------- 输出: --------------------*\
# <_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
# 1234567

  给.*后加上?号后,就使得.*的匹配进入非贪婪模式,当.*匹配到Hello后面的那个空格时,由于后面的(\d+)恰好可以匹配接下来的7个数字,所有.*就不继续匹配了。

当非贪婪模式的匹配在模式字符串的末尾时会匹配不到任何字符:

import re

content = 'http://weibo.com/comment/kEraCN'
result = re.match('http.*?comment/(.*?)', content)
result2 = re.match('http.*?comment/(.*)', content)
print('result', result.group(1))
print('result2', result2.group(1))

# /* ------------------- 输出: --------------------*\
# result 
# result2 kEraCN

修饰符

同样是上面用到过的字符串,给This之后加了换行符后,运行后会发现匹配失败。

import re

content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('He.*?(\d+).*?Demo$', content)
print(result.group(1))

这是因为, . 不能匹配换行符,这里只需加一个修饰符re.S, 即可修正这个错误:

result = re.match('He.*?(\d+).*?Demo$', content, re.S)

  这个re.S修饰符很有用,因为HTML节点内经常会有换行,加上它,就可以匹配节点与节点之间的换行了。

下面还有一些修饰符,可以在需要的情况下使用:

修饰符描述
re.I使匹配对大小写不敏感
re.L做本地化识别匹配
re.M多行匹配,影响^和$
re.S使.匹配包括换行在内的所有字符
re.U根据Unicode字符集解析字符。这个标志影响\w,\W,\b和\B
re.X该标志通过给予你更灵活的格式以便你将正则表达式写得更加易于理解

2. search()

match()方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败了。

如下,由于模式字符串开头并不和目标字符串开头匹配,所以匹配直接失败

import re

content = 'Hello 1234567 World_Thisis a Regex Demo'
result = re.match('(\d+).*?Demo$', content)
print(result)

# /* ------------------- 输出: --------------------*\
#  None

search()从前往后搜索,返回第一个匹配成功的子串:

import re

content = 'Hello 1234567 World_Thisis a Regex Demo'
result = re.search('(\d+).*?Demo$', content)
print(result)
print(result.group())

# /* ------------------- 输出: --------------------*\
# <_sre.SRE_Match object; span=(6, 39), match='1234567 World_Thisis a Regex Demo'>
# 1234567 World_Thisis a Regex Demo

3. findall()

  虽然search()可以返回匹配到的第一个子串,但如果想返回多个匹配成功的子串,那么可以使用findall()方法。

import re

html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">经典老歌列表</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href ="/3.mp3 ” singer="齐泰">往事随风</a>
</li>
<li data-view ="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''

results = re.findall('<li.*?href="(.*?)".*?singer="(.*)">(.*?)</a>', html, re.S)
print(results)
print(type(results))
for result in results:
    print(result)
    print(result[0], result[1], result[2])

# /* ------------------- 输出: --------------------*\
# [('/2.mp3', '陈慧琳">记事本</a></li>\n<li data-view="5">\n<a href="/6.mp3" singer="邓丽君', '但愿人长久')]
# <class 'list'>
# ('/2.mp3', '陈慧琳">记事本</a></li>\n<li data-view="5">\n<a href="/6.mp3" singer="邓丽君', '但愿人长久')
# /2.mp3 陈慧琳">记事本</a></li>
# <li data-view="5">
# <a href="/6.mp3" singer="邓丽君 但愿人长久

4. sub()

  除了使用正则表达式提取信息外,有时候还需要借助它来修改文本。比如,想要把一串文本中的所有数字都去掉,如果只用字符串的replace()方法,那就太烦琐了,这时可以借助sub()方法。

import re

html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">经典老歌列表</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href ="/3.mp3 ” singer="齐泰">往事随风</a>
</li>
<li data-view ="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''

# 将目标字符串中与'<a.*?>|</a>'匹配的部分替换为空串''
html = re.sub('<a.*?>|</a>', '', html)
print(html)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
for result in results:
    print(result.strip())

# /* ------------------- 输出: --------------------*\
# <div id="songs-list">
# <h2 class="title">经典老歌</h2>
# <p class="introduction">经典老歌列表</p>
# <ul id="list" class="list-group">
# <li data-view="2">一路上有你</li>
# <li data-view="7">
# 沧海一声笑
# </li>
# <li data-view="4" class="active">
# 往事随风
# </li>
# <li data-view ="6">光辉岁月</li>
# <li data-view="5">记事本</li>
# <li data-view="5">
# 但愿人长久
# </li>
# </ul>
# </div>
# 一路上有你
# 沧海一声笑
# 往事随风
# 光辉岁月
# 记事本
# 但愿人长久

5. complie()

complie()可以将可以将正则表达式编译为正则表达式对象,以重复利用模式字符串。

import re

content1 = '2016-12-15 12:00'
content2 = '2016-12-17 12:55'
content3 = '2016-12-22 13:21'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
print(result1, result2, result3)

# /* ------------------- 输出: --------------------*\
# 2016-12-15  2016-12-17  2016-12-22 

  事实上,complie()中也可以传入re.S等修饰符,这样match()和search()中使用正则表达式就不用重复添加修饰符了。这也可以看出,complie()实际上是对正则表达式本身做了一层封装。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python爬虫基础(一) —— 基本爬虫库的使用 的相关文章

  • js闭包的作用和应用的学习

    什么是闭包 一个函数和对其周围状态 xff08 lexical environment xff0c 词法环境 xff09 的引用捆绑在一起 xff08 或者说函数被引用包围 xff09 xff0c 这样的组合就是闭包 xff08 closu
  • css面试题布局

    不试试怎么知道自己行不行 昨天加了张鑫旭的微信 xff0c 我草贼开心 xff0c 发现他星期六会直播 xff0c 一下就是我看直播学到的一些总结 那么是什么呢 xff1f 其实就是一个简单的左右排版 xff0c 在张老师的讲了4种不是很好
  • 获取css的方法区别

    不试试怎么知道自己不可以 xff1f 对吧 首先我们要知道css在HTML中有多少总方法 xff1f 呵呵大家都知道的 行内 xff1a 顾名思义就是和标签在同一行 lt div class 61 34 text 34 style 61 3
  • 关于offsetLeft和offsetTop的兼容性问题

    不试一下怎么知道自己不可以 xff1f 首先我们要看下offsetLeft和offsetTop他们两的API的作用 xff1b 元素相对于offsetParent的左边距和上边距 xff08 为什么没有bottom xff0c right呢
  • js深度拷贝和浅度拷贝的深入理解

    首先我们来说说什么是拷贝 xff1a 就是复制的同时加上了传值 然后问题就来了什么是有深度的什么是浅度的 xff0c 在想要了解我们这个问题之前我们先来了解一下下面的一个知识点 基本类型传递 xff0c 引用类型传递 首先我们来看下基本类型
  • npm的基本使用

    npm的下载 npm的下载其实就是把node js 百度下node官网 下载好了那么npm就附带下载好了 检查是否下载好 window 43 r 后输入cmd打开终端 xff0c 在终端中输入node v xff1b npm v 他们会输出
  • 从 (a==1&&a==2&&a==3) 成立中看javascript的隐式类型转换

    几天上班看到一个题目就是 if a 61 61 1 amp amp a 61 61 2 amp amp a 61 61 3 console log 34 a等于什么才会输出这一句话呢 xff1f 34 当a为什么的时候输出 xff1a a等
  • Bootstrap实用功能总结

    导航栏 xff1a navbar 导航栏容器可以包含以下几个常用组成 xff1a 1 品牌LOGO xff08 navbar brand xff09 2 导航菜单 xff08 navbar nav xff09 3 导航文本 xff08 na
  • 微信小程序的AJAX初次体验

    GET请求 微信小程序用GET传送数据 微信小程序通过 wx request发送ajax请求 wx request url app globalData pubSiteUrl 43 39 user information get infor
  • vue总结系列 ------ 组件之间的传值

    原因 半年前开始学Vue学到了今天 xff0c 也没有机会好好整理一下自己的知识点 xff0c 因为上公司的项目不是依赖于Vue xff0c 还是在用JQ 和文件之间来传递代码 xff0c 所以其实在对vue的学习成面上来讲对我的帮助并不大
  • vue总结系列 --- 插槽slot

    前因 这个是我这个系列的第二篇 这一篇文章我也修改过三次 xff08 2019 9 10 xff09 我是想以vue官方文档为基础 xff0c 来进行理解 xff0c 有人说有官方文档 xff0c 还要写自己的文章干嘛 xff0c 我的用意
  • vue总结系列 --- 生命周期

    前言 在总结其他的时候发现还是应该先复习vue的生命周期 xff0c 所以就先把生命周期先复习完了 经过一系列的视频 xff0c 文档我把我的总结写一下生命周期分为3个阶段 xff1a 创建 xff0c 更新 xff0c 和销毁 我们看图说
  • vue总结系列 ---- 响应式原理

    检测变化 vue是数据驱动的视图框架DOM是通过数据映射的 xff0c 只有数据改变 xff0c DOM才改变 那么数据是怎么来的呢 xff1f 1 来自父元素的属性 xff08 prop xff09 2 来自组件的自身状态 xff08 d
  • Object.defineProperty()的学习了解

    背景 最近在总结vue系列的时候是看到响应原理的时候 看到一个新的知识点也就是我们的标题Object defineProperty 的时候 xff0c 好了话不多说 xff0c 我们来看看这个是怎么使用的 开始 strong Object
  • vue总结系列 ----- 单向数据流

    可能很多人都以为vue的双向绑定其实是错误的 xff0c vue真正的是单向数据流 xff0c vue的双向绑定只不过是语法糖 我的理解是 xff1a model层 xff1a data对象中的数据 xff0c 或后台传过来的数据 view
  • vue总结系列 ---- 在组件上的v-model单向数据流

    背景 目前是在复习vue原理的过程中 xff0c 前端负责人知道我最近在复习vue xff0c 跟我说要我看组件上的v model 我一听本来是不想放在心上的 xff0c 刚好那天晚上没什么事干想看一下 xff0c 毕竟负责人 xff0c
  • ES6 函数扩展

    参数默认值 也就是说现在ES6对函数中的参数添加了默认值 我们在ES5种的处理 function Fn a b b 61 b 34 nodeing 34 return a 43 b console log Fn 34 hello 34 这样
  • ES6 对象扩展

    对象简写 对象中又分了属性和方法的简写 在es5中 xff0c 有这样一种写法 var name 61 34 xiaoqiang 34 var age 61 12 var obj 61 name name age age 在es6中 xff
  • Bootstrap基础学习笔记

    网格系统 row定义一行 col均分列数 xff0c 最多一行12列 每列左右间隙各15px col 1到12 定义在所有屏幕下的列宽 col sm md lg xl 1到12 定义在指定屏幕下该列占据的列宽 xff0c sm 屏幕 gt
  • ES6 Symbol用法

    Symbol用法 什么是Symbol Symbol是es6中一种新增加的数据类型 xff0c 它表示独一无二的值 es5中我们把数据类型分为基本数据类型 xff08 字符串 数字 布尔 undefined null xff09 和引用数据类

随机推荐

  • img标签中的src在绝对引用的时候的问题

    昨天晚上我一个朋友目前在培训 xff0c 他在群里问了下img标签如何绝对路径引用 xff0c 我当时就笑了这个就是培训机构的老师 xff0c 就大概看了一下就告诉我朋友那里错了 xff0c 但是却出来不 xff0c 我就想自己写一个dem
  • 在vue-cli中使用vue-router的学习笔记

    以前不会vue cli的时候学过router xff0c 当时的写法和在vue cli中的写法还是有一些不一样的 xff0c 但是我以后应该还是会用vue的单文件写小程序啊什么的所以我就吧我学习的过程全部记录下来 router创建 那么问题
  • js中bind()使用详情

    前言 最近在在搞React的时候有用到bind 的时候 xff0c 因为他的用法其实我还一直不是特别的清楚 xff0c 所以今天我把bind 他的用法和我遇到的结合起来这样来写一个博客 xff0c 这样应该可以加深自己的印象同时可以来跟好的
  • var let const 详细区别

    用了ES6已经有一段事件了 xff0c 也看了很多文档 xff0c 以前觉得不用写一个文档总结 xff0c 但是经过一段时间的接触以后 xff0c 认为自己还是有必要去吧他们的区别详详细细的总结一下 块级作用域 白话一点就是在 中就是一个块
  • Git 速查表

    配置 git config global user name 34 lt 姓名 gt 34 设置提交者姓名 git config global user email 34 lt 邮箱 gt 34 设置提交者邮箱 这个有什么用呢 xff1f
  • async比Promise好在什么地方

    什么是Promise xff1f Promise是ES6中的异步编程解决方案 xff0c 在代码中表现为一个对象 xff0c 可以通过构造函数Promise来实例化 xff0c 有了Promise对象 xff0c 可以将异步操作以同步的流程
  • css面试题----css测试9

    每个星期6都会去去看张鑫旭直播写一些小demo然后再去吧写每天学习到的东西 xff0c 心得记下来 xff0c 并且会长期去完成这个任务 IT这个东西真的是要去强迫自己学学习一些好的东西 xff0c 多去优化代码 xff0c 而不是去停滞不
  • css面试题----DOM基础测试34

    这个其实是上上个星期张鑫旭直播的内容 xff0c 我吧我不会的内容总结一下 xff0c 从而来分享给大家 题目 第一问 document querySelectorAll 39 a 39 第二问 1 有bug当有这个href属性但没属性值
  • fon in 和 for of 的区别

    for 循环 其实他一般情况下是根据数组 xff0c 类数组的length的属性值去循环 for in 一般的作用是枚举把key枚举出来 xff0c 但是当我们枚举数组 xff0c 或者字符串的时候会把原型上的方法枚举出来 Object p
  • 词云图wordcloud学习笔记

    词云图 也叫文字云 是对文本中出现频率较高的 关键词 予以视觉化的展现 词云图过滤掉大量的低频低质的文本信息 使得浏览者只要一眼扫过文本就可领略文本的主旨 github https github com amueller word clou
  • ++a-a++解析

    有题目当a为1的时候 43 43 a a 43 43 为多少答案为0 我们再输出a这个时候a等于3 为什么呢 xff1f 运算顺序 前置递增 减 大于 数字运算和后置递增 减 大于 比较 布 大于 逻辑 或 且 大于 赋值 好当我们把运算顺
  • sync修饰符的使用

    为什么使用sync 再vue中官网的介绍 xff1a 我们可能需要对一个 prop 进行 双向绑定 不幸的是 xff0c 真正的双向绑定会带来维护上的问题 xff0c 因为子组件可以修改父组件 xff0c 且在父组件和子组件都没有明显的改动
  • vue中 methods computed watch filters区别

    在vue中事件 xff0c 计算属性 xff0c 帧听器 xff0c 过滤器的区别 其实共同点 xff1a 修改数据 事件methods和计算属性computed 作用 xff1a 对数据进行逻辑运算 区别 计算属性是基于它们的响应式依赖进
  • 前端面试题----js基础测试35

    得分 这个题目总共8分的我只有3分 xff0c 但是说实话我写这个题目的时候信心爆棚 xff0c 我觉得我自己应该是写出来的的 xff0c 但是可惜 解析 第一题 正解 xff1a 1 encodeURI 函数假设参数是完整的 URIs x
  • 前端面试题----DOM测试35

    得分 这个题目8分我5分 重新复习 HTML lt form id 61 34 loginForm 34 action 61 34 account login 34 method 61 34 POST 34 gt lt p gt 账号 xf
  • 前端小测---css基础测试10

    得分 总共8分得了6分有一个背景样式没处理好 重点 无js使用details和summary组合动画处理 xff0c 使用max height 0来过渡 HTML lt div class 61 34 container 34 gt lt
  • 前端小测试---- 图片上传

    得分 8分我自己得了4分 第一问 xhr onprogress和xhr upload onprogress的区别 xff1a 这两个都能显示进度百分比 xff0c 但是 xff0c 前者显示的是服务器返回的数据 xff0c 后者是发送给服务
  • js 部分代码注释规范

    普通注释 单行 单行注释 文字和 有一个空格 多行 多行注释 1 总是再多行注释的结束符前留一个空格 使星号对齐 2 不要把注释写再多行注释的开始符 xff0c 和结束符所在行 文档注释 Core模块提供最基础 最核心的接口 文档说明 64
  • js代码优化

    原文 xff1a https dmitripavlutin com unlearn javascript bad coding habits 一 xff1a 不要使用隐式类型转换 大多数运算符 43 61 61 不包括 61 61 61 再
  • Python爬虫基础(一) —— 基本爬虫库的使用

    文章目录 使用urllib库使用request模块发送请求1 使用urlopen urlopen data参数urlopen timeout参数 2 Request 3 高级用法验证代理Cookies 使用error模块处理异常1 URLE