1、Request库

HTTP测试工具:http://httpbin.org,以下的示例会以此为URL

属于第三方库,需要手动安装
pip install requests
基本用法
import requests

r = requests.get('http://www.baidu.com')
# 查看响应类型
print(type(r))
# 查看响应状态码
print(r.status_code)
# 查看响应内容的类型
print(type(r.text))
# 查看响应的内容
print(r.text)
# 查看cookies
print(r.cookies)

返回一个响应对象,然后分别输出响应对象类型、状态码、响应体内容的类型、 响应体的内容、Cookies。通过运行结果可以得知:响应对象的类型是requests.models.Response,响应体内容的类型是str,Cookies 的类型是RequestCookieJar。如果要发送其他类型的请求直接调用其对应的方法即可:

r = requests.post('https://www.baidu.com')
r = requests.put('https://www.baidu.com')
r = requests.delete('https://www.baidu.com')
r = requests.head('https://www.baidu.com')
r = requests.options('https://www.baidu.com')
GET请求

构建一个GET请求,请求http://httpbin.org/get(该网站会判断如果客户端发起的是GET请求的话,它返回相应的信息)

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

输出结果

{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.28.1",
"X-Amzn-Trace-Id": "Root=1-64f57ec6-49a5af517b0166dd7889d751"
},
"origin": "123.138.216.82",
"url": "http://httpbin.org/get"
}

如果要添加请求参数,比如添加两个请求参数,其中name值是germey,age值是20。虽然可以写成如下形式:

r = requests.get('http://httpbin.org/get?name=germey&age=20')

但较好的写法是下面这种写法:

import requests

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

输出

import requests

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

请求的URL最终被构造成了“http://httpbin.org/get?name=germey&age=20“

网页的返回内容的类型是str类型的,如果它符合JSON格式,则可以使用json( )方法将其转换为字典类型,以方便解析

import requests
r = requests.get('http://httpbin.org/get')
#str类型
print(type(r.text))
#返回响应内容的字典形式
print(r.json())
#dict类型
print(type(r.json()))

如果返回的内容不是JSON格式,调用json( )方法便会出现错误,抛出json.decoder.JSONDecodeError异常

Post请求

1)发送POST请求。

import requests
r = requests.post('http://httpbin.org/post')
print(r.text)

2)发送带有请求参数的POST请求。

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

结果

{
"args": {},
"data": "",
"files": {},
"form": { # 在POST请求方法中,form部分就是请求参数。 "age": "22",
"name": "germey"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "18",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.28.1",
"X-Amzn-Trace-Id": "Root=1-64f58064-3dc36bbb311e04a42a265c37"
},
"json": null,
"origin": "123.138.216.82",
"url": "http://httpbin.org/post"
}

3)设置请求头

import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0',
'my-test':'Hello'
}
r = requests.get('http://httpbin.org/get',headers=headers)
print(r.text)

结果

{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"My-Test": "Hello", # 请求头参数
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0",
"X-Amzn-Trace-Id": "Root=1-64f580a8-0188cb2528fd544a0f3ae23d"
},
"origin": "123.138.216.82",
"url": "http://httpbin.org/get"
}
响应

1)发送请求后,返回一个响应,它具有很多属性,通过它的属性来获取状态码、响应头、Cookies、响应内容等。如下

import requests

r = requests.get('https://www.baidu.com/')
# 响应内容(str类型)
print(type(r.text), r.text)
# 响应内容(bytes类型)
print(type(r.content), r.content)
# 状态码
print(type(r.status_code), r.status_code)
# 响应头
print(type(r.headers), r.headers)
# Cookies
print(type(r.cookies), r.cookies)
# URL
print(type(r.url), r.url)
# 请求历史
print(type(r.history), r.history)

2)响应码

状态码常用来判断请求是否成功,除了可以使用HTTP提供的状态码,requests库中也提供了一个内置的状态码查询对象,叫做 requests.codes,实际上两者都是等价的。示例如下:

import requests
r = requests.get('https://www.baidu.com/')
if not r.status_code==requests.codes.ok:
print('Request Fail')
else:
print('Request Successfully')

requests.codes对象拥有的状态码如下:

#信息性状态码
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',), #重定向状态码
300:('multiple_choices',),
301:('moved_permanently','moved','\\o-'),
302:('found',),
303:('see_other','other'),
304:('not_modified',),
305:('user_proxy',),
306:('switch_proxy',),
307:('temporary_redirect','temporary_moved','temporary'),
308:('permanent_redirect',), #客户端请求错误
400:('bad_request','bad'),
401:('unauthorized',),
402:('payment_required','payment'),
403:('forbiddent',),
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:('request_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',), #服务端错误状态码
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','bandwith'),
510:('not_extended',),
511:('network_authentication_required','network_auth','network_authentication')
爬取二进制数据

图片、音频、视频这些文件本质上都是由二进制码组成的,所以想要爬取它们,就要拿到它们的二进制码。以爬取百度的站点图标(选项卡上的小图标)为例:

import requests
#向资源URL发送一个GET请求
r = requests.get('https://www.baidu.com/favicon.ico')
with open('favicon.ico','wb') as f:
f.write(r.content)
#使用open( )方法,它的第一个参数是要保存文件名(可带路径),第二个参数表示以二进制的形式写入数据。运行结束之后,可以在当前目录下发现保存的名为favicon.ico的图标。同样的,音频和视频也可以用这种方法获取。
文件上传

requests可以模拟提交一些数据。假如某网站需要上传文件,我们也可以实现。

1)

import requests
#以二进制方式读取当前目录下的favicon.ico文件,并将其赋给file
files = {'file':open('favicon.ico','rb')}
#进行上传
r = requests.post('http://httpbin.org/post',files=files)
print(r.text)

2)Typora上传图片

import requests
import json
from sys import argv uploadUrl = 'https://upload.cnblogs.com/imageuploader/processupload?host=www.cnblogs.com' headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36",
"cookie":"" #此处填自己的cookie
}
# 类型映射
mimeMapping = {".png": 'image/png', '.gif': 'image/gif', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg'} for i in argv[1:]:
# 图片地址参数
imgPath = i # 对应的mime
mime = imgPath[imgPath.rindex("."):] file = [
("",("fileName", open(imgPath, "rb"), mimeMapping[mime]))
] response = requests.post(uploadUrl,headers = headers,files = file) data = json.loads(response.text)
print(data['message'])
处理Cookies

使用urllib处理Cookies比较复杂,而使用requests处理Cookies非常简单。

1)获取Cookies。

import requests
r = requests.get('https://www.baidu.com')
#打印Cookies对象
print(r.cookies)
#遍历Cookies
for key,value in r.cookies.items():
print(key+'='+value)
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
BDORZ=27315

通过响应对象调用cookies属性即可获得Cookies,它是一个RequestCookiesJar类型的对象,然后用items( )方法将其转换为元组组成 的列表,遍历输出每一个Cookies的名称和值。

2)使用Cookies来维持登录状态。以知乎为例,首先登录知乎,进入一个登录之后才可以访问的页面,在浏览器开发者工具中将Headers 中的Cookies复制下来(有时候这样直接复制的Cookies中包含省略号,会导致程序出错,此时可以在Console项下输document.cookie 即可得到完整的Cookie),在程序中使用它,将其设置到Headers里面,然后发送请求。

import requests
headers = {
'Cookie':'', # 自己的cookie信息
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0',
'Host':'www.zhihu.com'
}
r = requests.get('https://www.zhihu.com/people/xing-fu-shi-fen-dou-chu-lai-de-65-18',headers=headers)
print(r.text)

运行之后,结果中包含了登录后的内容,说明获取登录状态成功。

3)也可以通过cookies参数来设置,不过这样就需要构造RequestCookieJar对象,而且需要分割以下cookies,相对繁琐,但效果是一 样。

import requests

cookies =''
jar = requests.cookies.RequestsCookieJar()
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0',
'Host':'www.zhihu.com'
}
for cookie in cookies.split(';'):
key,value = cookie.split('=',1)
jar.set(key,value)
r = requests.get('https://www.zhihu.com/people/xing-fu-shi-fen-dou-chu-lai-de-65-18',headers=headers)
print(r.text)
会话维持

通过调用get( )或post( )等方法可以做到模拟网页的请求,但是这实际上是相当于不同的会话,也就是说相当于你用了两个浏览器打开不同的页面。如果第一个请求利用post( )方法登录了网站,第二次想获取登录成功后的自己的个人信息,又使用了一次get( )方法取请求个人信息,实际上,这相当于打开了两个浏览器,所以是不能成功的获取到个人信息的。为此,需要会话维持,你可以在两次请求时设置一样的Cookies,但这样很繁琐,而通过Session类可以很轻松地维持一个会话。

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

首先通过requests打开一个会话,然后通过该会话发送了一个get请求,该请求用于向cookies中设置参数number,参数值为123456789;接着又使用该发起了一个get请求,用于获取Cookies,然后打印获取的内容。

{
"cookies": {
"number": "123456789"
}
}
SSL证书验证

requests还提供了证书验证功能,当发送HTTP请求的时候,它会检查SSL证书,我们可以使用verify参数控制是否检查SSL证书。

1)请求一个HTTPS网站时,如果该网站的证书没有被CA机构信任,程序将会出错,提示SSL证书验证错误。对此,只需要将verify参数 设置为False即可。如下:

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

也可以指定一个本地证书用作客户端证书,它可以是单个文件(包含密钥和证书)或一个包含两个文件路径的元组。

import requests
#本地需要有crt和key文件(key必须是解密状态,加密状态的key是不支持的),并指定它们的路径,
response = requests.get('https://www.12306.cn',cert('/path/server.crt','/path/key'))
print(response.status_code)

在请求SSL证书不被CA机构认可的HTTPS网站时,虽然设置了verify参数为False,但程序运行可能会产生警告,警告中建议我们给它 指定证书,可以通过设置忽略警告的方式来屏蔽这个警告

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

或者通过捕获警告到日志的方式忽略警告

import logging
import requests
logging.captureWarnings(True)
response = requests.get('https://www.12306.cn',verify=False)
print(response.status_code)
代理设置

对于某些网站,在测试的时候请求几次,能正常获取内容。但是一旦开始大规模、频繁地爬取,网站可能会弹出验证码,或者跳转到登录验证页面,更有甚者可能会直接封禁客户端的IP,导致一定时间内无法访问。为了防止这种情况,我们需要使用代理来解决这个问题,这就需要用到proxies参数。

1)设置代理

https://www.89ip.cn/index_1.html

import requests

proxies = {
# 该代理服务器在免费代理网站上得到的,这样的网站有很多
'http': 'http://123.57.1.16:80',
'https': 'https://123.57.1.16:80'
}
try:
response = requests.get('http://httpbin.org/get', proxies=proxies)
print(response.text)
except requests.exceptions.ConnectionError as e:
print('Error', e.args)
{
"args": {
"show_env": ""
},
"headers": {
"Accept-Encoding": "",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.28.1",
"X-Amzn-Trace-Id": "Root=1-63156d33-528b16b838892ff15c5a4d2f",
"X-Forwarded-For": "123.57.1.16",
"X-Forwarded-Port": "80",
"X-Forwarded-Proto": "http"
},
"origin": "123.57.1.16", # 可以看到是由代理发起请求
"url": "http://httpbin.org/get?show_env"
}

2)如果代理需要使用HTTP Basic Auth,可以使用类似http://user:password@host:port这样的语法来设置代理。

import requests
proxies = {
"http":"http://user:password@161.35.4.201:80"
}
r = requests.get("https://www.taobao.com",proxies=proxies)
print(r.text)

3)除了基本的HTTP代理外,requests还支持SOCKS协议的代理。首先需要安装socks这个库:

pip3 install 'requests[socks]'
import requests
proxies = {
'http':'socks5://user:password@host:port',
'https':'socks5://user:password@host:port'
}
request.get('https://www.taobao.com',proxies=proxies)
超时设置

在本机网络状况不好或者服务器网络响应太慢甚至无响应时,我们可能会等待特别久的时间才可能收到响应,甚至到最后收不到响应而报错。为了应对这种情况,应设置一个超时时间,这个时间是计算机发出请求到服务器返回响应的时间,如果请求超过了这个超时时间还没有得到响应,就抛出错误。这就需要使用timeout参数实现,单位为秒。

1)指定请求总的超时时间

import requests
#向淘宝发出请求,如果1秒内没有得到响应,则抛出错误
r = requests.get('https://www.taobao.com',timeout=1)
print(r.status_code)

2)分别指定超时时间。实际上,请求分为两个阶段:连接(connect)和读取(read)。如果给timeout参数指定一个整数值,则超时时 间是这两个阶段的总和;如果要分别指定,就可以传入一个元组,连接超时时间和读取超时时间:

import requests
#向淘宝发出请求,如果连接阶段5秒内没有得到响应或读取阶段30秒内没有得到响应,则抛出错误
r = requests.get('https://www.taobao.com',timeout=(5,30))
print(r.status_code)

3)如果想永久等待,可以直接timeout设置为None,或者不设置timeout参数,因为它的默认值就是None。

import requests
#向淘宝发出请求,如果连接阶段5秒内没有得到响应或读取阶段30秒内没有得到响应,则抛出错误
r = requests.get('https://www.taobao.com',timeout=None))
print(r.status_code)
身份验证

使用requests自带的身份验证功能,通过HTTPBasicAuth类实现。

import requests
from requests.auth import HTTPBasicAuth s = requests.Session()
r = s.get('http://192.168.2.93:8481/#/login?redirect=%2F', auth=HTTPBasicAuth('admin', 'Hbis@123'))
print(r.status_code)

如果用户名和密码正确的话,返回200状态码;如果不正确,则返回401状态码。也可以不使用HTTPBasicAuth类,而是直接传入一个 元组,它会默认使用HTTPBasicAuth这个类来验证。

import requests

s = requests.Session()
r = s.get('http://192.168.2.93:8481/#/login?redirect=%2F', auth=('admin', 'Hbis@123'))
print(r.status_code)

requests还提供了其他验证方式,如OAuth验证,不过需要安装oauth包,安装命令如下:

import requests
from requests_oauthlib import OAuth1
url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
auth = OAuth1("YOUR_APP_KEY","YOUR_APP_SECRET","USER_OAUTH_TOKEN","USER_OAUTH_TOKEN_SECRET")
requests.get(url,auth=auth)
Prepared Request

在学习urllib库时,发送请求如果需要设置请求头,需要通过一个Request对象来表示。在requests库中,存在一个与之类似的类,称为Prepared Request。

from requests import Request,Session
url = 'http://httpbin.org/post'
data = {
'name':'germey'
}
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0'
}
s = Session()
req = Request('POST',url,data=data,headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)

这里引入了Request,然后用url、data和headers参数构造了一个Request对象,这时需要再调用Session的prepare_request( )方法将其转换为一个Prepared Request对象,然后调用send( )方法发送。这样做的好处时:可以利用Request将请求当作独立的对象来看待,这样在进行队列调度时会非常方便,后面会用它来构造一个Request队列

示例

爬取豆瓣Top250

"""
爬取豆瓣电影
"""
import requests
import re file = 'movie.csv'
f = open(file, 'w', encoding='utf-8')
f.write('电影名称,导演,年份,电影评分,评论数\n') for page in range(0, 250, 25):
url = f'https://movie.douban.com/top250?start={page}'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36'
} response = requests.get(url, headers=headers)
text = response.text
# pattern1 = re.compile(
# r'<div class="item">.*?<span class="title">(?P<item>.*?)</span>.*?<p class="">.*?(?P<auth>.*?)&nbsp;', re.S)
pattern = re.compile(
r'<div class="item">.*?<span class="title">(?P<item>.*?)</span>.*?<p class="">.*?导演: (?P<auth>.*?)&nbsp;.*?<br>'
r'(?P<year>.*?)&nbsp;.*?<span class="rating_num" property="v:average">(?P<core>.*?)</span>.*?<span>(?P<comment>.*?)人评价</span>',
re.S)
result = pattern.finditer(text)
for x in result:
item = x.group('item').strip()
auth = x.group('auth').strip()
year = x.group('year').strip()
core = x.group('core').strip()
comment = x.group('comment').strip()
list = [item, auth, year, core, comment]
context = ','.join(list) + '\n'
f.write(context)
print(f"链接:{url}爬取完毕\n") f.close()

爬取数据

import json

import requests

url = 'http://192.168.2.93:8481/api/v5/login'
data = {
"username": "sun",
"password": "NsWf7IeojknkNmBenjyZIHfE2eKJKge4LYF66lhVuGCGhpg1pWEer6IjlOWvk0mG+at5ksNfgk5R2d/DtZZPSkQ53U727AznwLeHZ6sDPuSMITSCJUoBzj9dYSDXUJXjNeY992UBl16sMtVC9IkSp5bRyNhii8te3az1lZt1zaA="
}
headers = {
'Referer': 'http://192.168.2.93:8481/',
'Content-Type': 'application/json',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJpcCI6IjE5Mi4xNjguMy40MiIsIm5hbWUiOiLnrqHnkIblkZgiLCJleHAiOjE2OTM0NzEyNjYsInVzZXJJZCI6IjEiLCJqdGkiOiIwNDhmM2YyNy00ZmUyLTRjYTAtODExOC1lNWI0NmNmNTlkMzIiLCJjbGllbnRfaWQiOiJhZG1pbiIsInVzZXJuYW1lIjoiYWRtaW4ifQ.loNAyIl0FRb-qMGNK_WJsDrqJdmOfSXXGygaEmYOwrU'
} with requests.Session() as session:
session.headers.update(headers)
response = session.post(url, data=json.dumps(data))
if response.status_code == 200:
print('登陆成功')
post = session.get('http://192.168.2.93:8481/api/v5/cluster/findById?clusterId=141')
print(post.json())
# 查看日志
get = session.get(
'http://192.168.2.93:8481/api/v5/log/findLongPage?startTime=2023-07-21+17:51:09&endTime=2023-08-21+17:51:09&username=&text=')
print(get.json())
else:
print("登录失败")

爬取二进制图片

import requests
import os def spider(page):
global pic_name
url = f'https://www.pexels.com/zh-cn/api/v3/users/320381804/media/recent?per_page=12&page={page}&seo_tags=true'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
'Referer': 'https://www.pexels.com/zh-cn/@emre-akyol-320381804/gallery/',
'Secret-Key': 'H2jk9uKnhRmL6WPwh89zBezWvr', # 关键
'Cookie': '__cf_bm=GKFhiRbFocgTe4tZBxPJ0k85nil.L39sq6J3XkU.rhA-1692671105-0-Acp7DNkzsbV1Wo3Q8D1x3ohwYIsEJunyaBuVtQ3AFdNjokPHMj7AejJ9HfS251NSaaBHd8Nn+JTcJDOYXyejwWs=; _gid=GA1.2.1719033680.1692671105; _sp_ses.9ec1=*; _hjFirstSeen=1; _hjIncludedInSessionSample_171201=0; _hjSession_171201=eyJpZCI6IjFjOGIzOWZkLTA0NWUtNDY4Ni1hY2I3LThlYjE3MWQzMGNjYiIsImNyZWF0ZWQiOjE2OTI2NzExMTM3NjAsImluU2FtcGxlIjpmYWxzZX0=; _hjAbsoluteSessionInProgress=0; OptanonAlertBoxClosed=2023-08-22T02:25:14.309Z; _hjSessionUser_171201=eyJpZCI6IjQ1ODU2MDlmLTdmNDktNTFkMi05MGNiLWQxNmNjMjFhYjE0YSIsImNyZWF0ZWQiOjE2OTI2NzExMTM3NTQsImV4aXN0aW5nIjp0cnVlfQ==; cf_clearance=EyheRqx2Tumh.M2FaKkSr5E.MGrbCiKg5ANP0imlLls-1692671123-0-1-5d1dd351.73fb3ba.47546780-0.2.1692671123; _sp_id.9ec1=17087147-0866-420b-a564-8e85edd3c920.1692671112.1.1692671172..6f3c33d1-1697-4d0b-9a66-8f80467e82f5..4ecd1c0e-4bc7-4552-8ad5-cbe471c11a6c.1692671121004.6; OptanonConsent=isGpcEnabled=0&datestamp=Tue+Aug+22+2023+10%3A26%3A12+GMT%2B0800+(%E4%B8%AD%E5%9B%BD%E6%A0%87%E5%87%86%E6%97%B6%E9%97%B4)&version=202301.1.0&isIABGlobal=false&hosts=&landingPath=NotLandingPage&groups=C0001%3A1%2CC0002%3A1%2CC0003%3A1&geolocation=CN%3BSN&AwaitingReconsent=false; _ga=GA1.1.1140262214.1692671105; _ga_8JE65Q40S6=GS1.1.1692671113.1.1.1692671173.0.0.0'
}
response = requests.get(url, headers=headers)
data = response.json()['data']
for item in data:
try:
attributes = item['attributes']
last_name = attributes['user']['last_name']
download_url = attributes['image']['download_link']
pic_url = str.split(download_url, '?')[0]
print(f'用户:{last_name},图片地址:{pic_url}') content = requests.get(pic_url, headers=headers).content
pic_name = os.path.basename(pic_url)
with open(f'image\\{pic_name}', 'wb') as f:
f.write(content)
print(f'图片:{pic_name}下载成功!')
except Exception as e:
print(f'图片:{pic_name}下载失败,{str(e)}') if __name__ == '__main__':
for i in range(1, 11):
spider(i)

代理

import re

import requests

def get_proxy_Ip():
# url = 'https://www.89ip.cn/index_1.html'
api_url = 'http://api.89ip.cn/tqdl.html?api=1&num=1000&port=&address=&isp='
html = requests.get(api_url).text
re_compile = re.compile(r'\d+.\d+.\d+.\d+:\d+')
return re_compile.findall(html) def get_request(type, url, proxy):
return requests.request(method=type, url=url, proxies=proxy) def spider(url, ips):
while 1:
for ip in ips:
try:
proxy = {
'http': f'http://{ip}',
'https': f'https://{ip}'
}
response = get_request('get', url, proxy)
if response.status_code == '200':
return response
except Exception as e:
print(f'代理:{ip} 可能失效:{str(e)}') if __name__ == '__main__':
# url = 'https://movie.douban.com/top250'
url = 'http://www.baidu.com'
res = spider(url, get_proxy_Ip())
print(res.text)

2、BS4

安装

from bs4 import BeautifulSoup

获取网页信息

可以使用urlib或者request获取

import requests
url = "https://www.baidu.com"
r1 = requests.get(url,'lxml')
r1.encoding='utf-8'
#print (r1.text)
bs_1=BeautifulSoup(r1.text,'lxml')
#print(bs_1)

第一个参数为html信息,第二个是bs4自带的解析器,如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的

然后通过这个对象来实现对获取到的源码进行筛选和处理

print(bs_1.prettify()) #格式化输出全部内容
print(bs_1.title) # #标签名有html,head,title,meta,body,script,style等等

实例1:

from bs4 import BeautifulSoup

html = """
<ul>
<li><a type='sun' href='zhangwuji.com'>张无忌</a></li>
<li><a type='sun' href='zhangwuji1.com'>张无忌1</a></li>
<li><a href='zhangwuji2.com'>张无忌2</a></li>
<li><a href='zhangwuji3.com'>张无忌3</a></li>
</ul>
"""
soup = BeautifulSoup(html, 'html.parser')
# 查找所有的'a'标签
all_a = soup.find_all('a')
print(all_a)
# 查找第一个'a'标签
single_a = soup.find('a')
print(single_a)
# 查找第一个'a'标签,筛选
single_a_ = soup.find('a', attrs={'type': 'sun'})
print(single_a_)
# 遍历所有的'a'标签列表
for a in all_a:
context = a.text
link = a.get('href')
print(context, link)

示例2:

index.html

<!DOCTYPE html>
<html lang="en" xmlns="">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<ul>
<li id="l1">张三</li>
<li id="l2">李四</li>
<li>王五</li>
<a href="" id="" class="a1">尚硅谷</a>
<span>嘿嘿嘿</span>
</ul>
</div>
<a href="www.baidu.com" title="a2">百度</a>
<div id="d1">
<span>
哈哈哈
</span>
</div>
<p id="p1" class="p1">呵呵呵</p>
</body>
</html>
from bs4 import BeautifulSoup

# 通过解析本地文件 来将bs4的基础语法进行讲解
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码 BeautifulSoup使用的是lxml内核
soup = BeautifulSoup(open('index.html', encoding='utf-8'), 'lxml') # 根据标签名查找节点
# 找到的是第一个符合条件的数据
print(soup.a)
# 获取标签的属性和属性值
print(soup.a.attrs)
<a class="a1" href="" id="">尚硅谷</a>
{'href': '', 'id': '', 'class': ['a1']}
find示例
from bs4 import BeautifulSoup

# 通过解析本地文件 来将bs4的基础语法进行讲解
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码 BeautifulSoup使用的是lxml内核
soup = BeautifulSoup(open('index.html', encoding='utf-8'), 'lxml') # 获取第一个值
print(soup.find('a'))
# 根据title的值来找到对应的标签对象
print(soup.find('a', title='a2'))
# 根据class的值来找到对应的标签对象 注意的是class需要添加下划线
print(soup.find('a', class_='a1'))
# 根据指定的属性找对应的标签对象
print(soup.find('a', attrs={'href': 'www.baidu.com'}))
find_all 示例
# find_all  返回的是一个列表 并且返回了所有的a标签
print(soup.find_all('a')) # 如果想获取的是多个标签的数据 那么需要在find_all的参数中添加的是列表的数据
print(soup.find_all(['a','span'])) # limit的作用是查找前几个数据
print(soup.find_all('li',limit=2))
select(推荐)

select方法返回的是一个列表(符合条件的所有数据)

# select方法返回的是一个列表  并且会返回多个数据
print(soup.select('a')) # 可以通过.代表class 我们把这种操作叫做类选择器
print(soup.select('.a1')) # 可以通过#代表id 我们把这种操作叫做id选择器
print(soup.select('#l1'))
from bs4 import BeautifulSoup

# 通过解析本地文件 来将bs4的基础语法进行讲解
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码 BeautifulSoup使用的是lxml内核
soup = BeautifulSoup(open('index.html', encoding='utf-8'), 'lxml') # 属性选择器---通过属性来寻找对应的标签
# 查找到li标签中有id的标签
print(soup.select('li[id]')) # 查找到li标签中id为l2的标签
print(soup.select('li[id="l2"]'))
from bs4 import BeautifulSoup

# 通过解析本地文件 来将bs4的基础语法进行讲解
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码 BeautifulSoup使用的是lxml内核
soup = BeautifulSoup(open('index.html', encoding='utf-8'), 'lxml') # (3)select(推荐)
# 层级选择器
# 后代选择器
# 找到的是div下面的li
print(soup.select('div li')) # 子代选择器
# 某标签的第一级子标签
# 注意:很多的计算机编程语言中 如果不加空格不会输出内容 但是在bs4中 不会报错 会显示内容
print(soup.select('div > ul > li'))
from bs4 import BeautifulSoup

# 通过解析本地文件 来将bs4的基础语法进行讲解
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码 BeautifulSoup使用的是lxml内核
soup = BeautifulSoup(open('index.html', encoding='utf-8'), 'lxml') # (3)select(推荐)
# 找到a标签和li标签的所有的对象
print(soup.select('a,li')) # 节点信息
# 获取节点内容
obj = soup.select('#d1')[0]
# 如果标签对象中 只有内容 那么string和get_text()都可以使用
# 如果标签对象中 除了内容还有标签 那么string就获取不到数据 而get_text()是可以获取数据
# 我们一般情况下 推荐使用get_text()
print(obj.string)
print(obj.get_text())
from bs4 import BeautifulSoup

# 通过解析本地文件 来将bs4的基础语法进行讲解
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码 BeautifulSoup使用的是lxml内核
soup = BeautifulSoup(open('index.html', encoding='utf-8'), 'lxml') # (3)select(推荐)
# 节点的属性
obj = soup.select('#p1')[0]
# name是标签的名字
print(obj.name)
# 将属性值左右一个字典返回
print(obj.attrs)
from bs4 import BeautifulSoup

# 通过解析本地文件 来将bs4的基础语法进行讲解
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码 BeautifulSoup使用的是lxml内核
soup = BeautifulSoup(open('index.html', encoding='utf-8'), 'lxml') # (3)select(推荐)
# 获取节点的属性
obj = soup.select('#p1')[0]
#
print(obj.attrs.get('class'))
print(obj.get('class'))
print(obj['class'])
import urllib.request
from bs4 import BeautifulSoup url = 'https://www.starbucks.com.cn/menu/' response = urllib.request.urlopen(url) content = response.read().decode('utf-8') soup = BeautifulSoup(content, 'lxml') # //ul[@class="grid padded-3 product"]//strong/text()
name_list = soup.select('ul[class="grid padded-3 product"] strong') for name in name_list:
print(name.get_text())

3. xpath

基本

lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高,基于路径的方式来获取元素和节点

三部分组成:

  • 路径表达式: 基础,用于描述元素和节点的位置关系,如/bookstore/book[1]/title表示选择bookstore元素下的第一个book元素的title节点。

    a = """
    <bookstore>
    <book>
    <title>Book 1</title>
    <price>30</price>
    </book>
    <book>
    <title>Book 2</title>
    <price>40</price>
    </book>
    <book>
    <title>Book 3</title>
    <price>25</price>
    </book>
    </bookstore> """
    from lxml import etree
    root = etree.XML(a)
    # 如果有多个book标签,则返回一个列表
    books = root.xpath("/bookstore/book/title")
    # [<Element title at 0x1047d90b8>
  • 选择器:

    通过添加谓词来筛选元素和节点

    /bookstore/book[price>35]/title表示选择bookstore元素下价格大于35的book元素的title节点
  • 函数:

    XPath支持多种函数来处理节点和元素。例如,count(/bookstore/book)函数可以计算bookstore元素下的book元素数量

    print(root.xpath("count(/bookstore/book)"))

安装、导入库

pip install lxml
from lxml import etree

实例化一个etree的多种方式

# 1. 直接传入字符串
str_etree = etree.HTML(a) # etree.HTML会尝试根据HTML的宽松语法解析输入的字符串
xml_etree = etree.XML(a) #求标签必须正确嵌套和闭合
# 2. 传入文件路径
file_etree = etree.parse("./book.xml")
# 3. 传入文件对象
file_object = open("./book.xml")
# 4. 传入etree.Element对象
root_etree = etree.fromstring(a)

表达式

XPath 表达式 描述
nodename 选择指定节点名为 nodename 的所有元素。
/ 从根节点开始选择。
// 选择匹配选择的任何位置的节点。
. 选择当前节点。
.. 选择当前节点的父节点。
@attribute 选择具有指定属性名 attribute 的所有元素。
@* 选择所有具有属性的元素。
[@attribute='value'] 选择具有指定属性名为 attribute,且属性值为 value 的所有元素。
[@attribute1='value1' and @attribute2='value2'] 选择具有指定属性名和属性值的所有元素。
[@attribute='value']/child::node() 选择具有指定属性名和属性值的元素的子节点。
//child::node() 选择文档中的所有子节点。
//child::element 选择文档中的所有元素节点。
child::node()[position()=1] 选择文档中的第一个子节点。
child::*[position()=last()] 选择文档中的最后一个元素节点。
child::text() 选择文档中的所有文本节点。
child::comment() 选择文档中的所有注释节点。
descendant::node() 选择当前节点的后代节点(包括子孙节点)。
ancestor::node() 选择当前节点的祖先节点(包括父辈节点)。
parent::node() 选择当前节点的父节点。
from lxml import etree

html = """
<book>
<id>1</id>
<name>蔡依林</name>
<price>1.23</price>
<nick>臭豆腐</nick>
<author>
<nick id="10086">周大强</nick>
<nick id="10081">周杰伦</nick>
<nick class="jay">周大福</nick>
<nick class="jolin">蔡依林</nick>
<div>
<nick>林俊杰</nick>
</div>
</author>
<partner>
<nick href="www.baidu.com" id="ppc">胖胖陈</nick>
<nick id="ppbc">胖胖不陈</nick>
</partner>
</book>
"""
# 构建xml树
et = etree.XML(html)
root = et.xpath('/book') # 表示根节点
son = et.xpath('/book/name') # 在xpath中间的/表示的是儿子
son_text = et.xpath('/book/name/text()')[0] # text()取文本
nick_all = et.xpath('/book//nick') # //表示的是子孙后代
nick = et.xpath('/book/*/nick/text()') nick_class = et.xpath('/book/author/nick[@class="jay"]/text()') # []表示属性筛选,@属性名=值
id = et.xpath('/book/partner/nick/@id') # 取属性值,比如id
href = et.xpath('/book/partner/nick/@href') # 取属性值,比如href
ID = et.xpath('/book/partner/nick[2]/text()') # [i] 表述取第i个
nick_ppbc = et.xpath('/book/partner/nick[@id="ppbc"]/text()')
print(nick_ppbc)

实战

import requests
from lxml import etree
url='https://sh.58.com/ershoufang/'
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.7 Safari/537.36'}
page_test=requests.get(url=url,headers=headers).text
tree=etree.HTML(page_test)
#先看图二的解释,这里li有多个,所里返回的li_list是一个列表
li_list=tree.xpath('//ul[@class="house-list-wrap"]/li')
#这里我们打开一个58.txt文件来保存我们的信息
fp=open('58.txt','w',encoding='utf-8')
for li in li_list:
#这里 ./是对前面li的继承,相当于li/div...
title=li.xpath('./div[2]/h2/a/text()')[0]
print(title+'\n')
fp.write(title+'\n')
fp.close()

Python爬虫之数据解析的更多相关文章

  1. Python爬虫:数据解析 之 xpath

    资料: W3C标准:https://www.w3.org/TR/xpath/all/ W3School:https://www.w3school.com.cn/xpath/index.asp 菜鸟教程 ...

  2. python爬虫---爬虫的数据解析的流程和解析数据的几种方式

    python爬虫---爬虫的数据解析的流程和解析数据的几种方式 一丶爬虫数据解析 概念:将一整张页面中的局部数据进行提取/解析 作用:用来实现聚焦爬虫的吧 实现方式: 正则 (针对字符串) bs4 x ...

  3. python 爬虫与数据可视化--python基础知识

    摘要:偶然机会接触到python语音,感觉语法简单.功能强大,刚好朋友分享了一个网课<python 爬虫与数据可视化>,于是在工作与闲暇时间学习起来,并做如下课程笔记整理,整体大概分为4个 ...

  4. 利用python将excel数据解析成json格式

    利用python将excel数据解析成json格式 转成json方便项目中用post请求推送数据自定义数据,也方便测试: import xlrdimport jsonimport requests d ...

  5. 05 Python网络爬虫的数据解析方式

    一.爬虫数据解析的流程 1.指定url 2.基于requests模块发起请求 3.获取响应中的数据 4.数据解析 5.进行持久化存储 二.解析方法 (1)正则解析 (2)bs4解析 (3)xpath解 ...

  6. 【Python】 用python实现定时数据解析服务(前言)

    一.Why do it? 背景:项目里上传上来的数据都是未解析的数据,而且数据量还算挺庞大的,每天上传的数据有5kw左右,如果用数据库自带的作业来解析的话,数据库会造成严重的阻塞.因此打算把数据读到外 ...

  7. Python爬虫 股票数据爬取

    前一篇提到了与股票数据相关的可能几种数据情况,本篇接着上篇,介绍一下多个网页的数据爬取.目标抓取平安银行(000001)从1989年~2017年的全部财务数据. 数据源分析 地址分析 http://m ...

  8. Python爬虫与数据图表的实现

    要求: 1. 参考教材实例20,编写Python爬虫程序,获取江西省所有高校的大学排名数据记录,并打印输出. 2. 使用numpy和matplotlib等库分析数据,并绘制南昌大学.华东交通大学.江西 ...

  9. 在我的新书里,尝试着用股票案例讲述Python爬虫大数据可视化等知识

    我的新书,<基于股票大数据分析的Python入门实战>,预计将于2019年底在清华出版社出版. 如果大家对大数据分析有兴趣,又想学习Python,这本书是一本不错的选择.从知识体系上来看, ...

  10. Python爬虫 | re正则表达式解析html页面

    正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"). 正则表达式通常被用来匹配.检索.替换和 ...

随机推荐

  1. JVM学习笔记之栈区

    JVM学习笔记之栈区 本文主要内容: 栈是什么?栈帧又是什么?在JVM中,main方法调用say方法后,是怎么运行的?本文将详细讲解栈.希望大家学了之后,对栈有更深的了解. 心法:在JVM中,栈管运行 ...

  2. Innodb 单表索引查询和连接查询效率分析

    一.MySQL查询访问方法 mysql执行查询语句的方式叫做访问方法或访问类型,这些访问类型具体为 const.ref.range.index.all等. 同一个查询语句可以使用多种不同的访问方法来执 ...

  3. python 浅拷贝与深拷贝

    赋值引用 >>> a= {1:[1,2]}>>> b = a>>> b[2]=3>>> b {1: [1, 2], 2: 3} ...

  4. 使用 Microsoft.Extensions.ServiceDiscovery 进行服务发现并调用

    简介 在现代微服务架构中,服务发现(Service Discovery)是一项关键功能.它允许微服务动态地找到彼此,而无需依赖硬编码的地址.以前如果你搜 .NET Service Discovery, ...

  5. CSIG青年科学家会议圆满举行,合合信息打造智能文档处理融合研究新范式

          近期,第十九届中国图象图形学学会青年科学家会议(简称"会议")在广州召开.会议由中国图象图形学学会(CSIG)主办,琶洲实验室.华南理工大学.中山大学.中国图象图形学学 ...

  6. Angular Material 18+ 高级教程 – Get Started

    前言 本编是 Angular Material 教程的开篇,我先介绍一下这个教程. 首先,Angular Material 教程不会像 Angular 教程那么注重原理,也很少会逛源码. 所以,如果你 ...

  7. ASP.NET Core Library – HtmlSanitizer

    介绍 要输出 Raw HTML 最好是先消毒一下. 使用 Library 就可以了. 参考 Github – mganss / HtmlSanitizer 安装 nuget dotnet add pa ...

  8. HTML & CSS – Practice Projects

    前言 学完了 w3school 就要练练手了. 这篇是记入我学习的过程, 和知识点. update: 2022-02-27 用文章来表达太难了, 用视频比较合理. 所以我就没有继续写了. 这里记入几篇 ...

  9. 理解IO多路复用

    I/O 多路复用是什么? I/O 多路复用是用户程序通过复用一个线程来服务多个 I/O 事件的机制,我们也可以将他说成是一个线程服务多个文件描述符 fd,而 I/O 多路复用是在操作系统层面实现提供的 ...

  10. C++ cout打印输出 (解决输出乱码)

    cout打印输出 输出单份内容 // 输出单份内容 cout << "Hello World!" << endl; cout << 10 < ...