爬虫系列-request基本库的使用

34 篇文章 1 订阅
17 篇文章 0 订阅

上一篇博客中,我们了解了urllib的基本用法,但是它还是存在很多缺陷,比如处理网页验证和Cookies时,需要写通过类来实例化对象比较麻烦。为了更加方便地实现这些操作,就有了更为强大的库requests,对于它来说Cookies、登录验证、代理设置等操作都容易很多。

1.基本用法

它如何简单我下面举个例子你们可以看看:

import requests
response = requests.get('http://www.baidu.com/')
print(response.text)

在这里插入图片描述
短短几行也就把百度首页的源代码获取下来了,是不是很简单,这是一个很小的部分而已。我们还可以看获取的网页状态码等一些其他信息。

print(response.status_code)
print(type(response))
print(r.cookies)
print(type(r.text))

最终得到的结果:

200
<class 'requests.models.Response'>
<RequestsCookieJar[]>
<class 'str'>

我们可看到状态码是正常的,然后返回的文本信息也是字符串类型的。也可以查看请求的Response的类型。
requests使用get()方法完成了GET请求,这倒不算什么,更方便在与请求请求,比如POST,PUT,DELETE等请求,下面我们可以看看POST请求。

response = requests.post('http://www.iqianyue.com/mypost')
print(response.text)

返回的结果:

<html>
<head>
<title>Post Test Page</title>
</head>
<body>
<form action="" method="post">
name:<input name="name" type="text" /><br>
passwd:<input name="pass" type="text" /><br>
<input name="" type="submit" value="submit" />
<br />
</body>
</html>

是不是很简单,其实这是一小点而已,post(),put(),delete()这三个函数就能直接实现对上面三种方式的请求。

get请求

HTTP中最常见的请求之一就是GET请求,下面首先来详细了解一下利用requests构建GET请求的方法。直接用request.get()就可以了。上面我也举过例子了。

那么,对于GET请求,如果要附加额外的信息,一般怎样添加呢?比如现在想添加两个参数,其中name是germey,age是22。要构造这个请求链接,是不是要直接写成:

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

这样看起来很不人性化,而且构造的网址灵活性差。一般情况下,这种信息数据会用字典来存储。我们可以这样来构造:

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", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.18.4"
  }, 
  "origin": "113.57.74.32, 113.57.74.32", 
  "url": "https://httpbin.org/get?name=germey&age=22"
}

通过运行结果可以看到url构造成我们想要的形式了。http://httpbin.org/get?age=22&name=germey
另外,网页的返回类型实际上是str类型,但是它很特殊,是JSON格式的。所以,如果想直接解析返回结果,得到一个字典格式的话,可以直接调用json()方法。

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

运行结果是这样的:

<class 'str'>
{'headers': {'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.10.0'}, 'url': 'http://httpbin.org/get', 'args': {}, 'origin': '182.33.248.131'}
<class 'dict'>

但前提是返回结果是json()格式,如果不是这种格式直接解析的话会出现问题。
下面我们来写一两个简单的爬取让大家看看request如何进行get请求爬取并解析。

小实例
1.文本数据爬取

比如我们以知乎的一个页面为例https://www.zhihu.com/explore爬取下面的问题

import requests
from  lxml  import  etree

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'
}
r = requests.get("https://www.zhihu.com/explore", headers=headers)
selector =etree.HTML(r.text)
title_list = selector.xpath('//div[@class="ExploreRoundtableCard-questionItem"]/a/text()')
print(title_list)

lxml 是一个解析库,后面我会专门单独来讲,通过上面这简单的几行代码,我就能完成基础的爬取,基本成功的提取了所有问题的内容,返回的结果是:

['信号频域和时域的关系是怎样的?',
 '什么是信号?',
 '信号与系统这门课程有何价值?',
 '为什么机器人研究了几十年,还是给人感觉没有太大进展?',
 '这种不考试,以娱乐为主的机器人教育对于中小学生及幼儿的意义何在?',
 '人形机器人的研究的意义是什么?',
 '公司招聘时号称弹性工作制,入职后部门领导却要求打卡上班,应该怎么办?',
 '对于工作 5 年以上的职场人来说,有哪些比工资低更危险的事?',
 '在你的行业里,有哪些看似「不职业」的行为其实是「非常职业」的表现?',
 '申请国外 PhD 的时候如何与教授套磁?',
 '科研工作者有哪些「新手常见错误」?',
 '如何成为一个不油腻的科研工作者?']
2.二进制数据爬取

在上面的例子中,我们抓取的是知乎的一个页面,实际上它返回的是一个HTML文档。如果想抓去图片、音频、视频等文件,应该怎么办呢?图片、音频、视频这些文件本质上都是由二进制码组成的,由于有特定的保存格式和对应的解析方式,我们才可以看到这些形形色色的多媒体。所以,想要抓取它们,就要拿到它们的二进制码。
举个例子https://github.com/favicon.ico这个是github的一个图标,当我们直接请求,然后打印返回的结果会乱码,因为我们直接打印会将图片直接转化为字符串肯定会乱码,我们下面这样做就没问题,而且在当前路径下回生成一个图标样式的文件。

import requests
r = requests.get("https://github.com/favicon.ico")
with open('favicon.ico', 'wb') as f:
    f.write(r.content)

在我们上面请求中,第一个知乎中添加了headers,也就是请求头,我们需要在请求头中添加user-agent,不然很有可能请求不到。也可以在headers这个参数中添加任意的其他字段信息。

5.响应

在python请求中,我们要通过返回的状态码对响应结果进行分析,查看是出了什么问题,下面我列出所有的状态码大家可以看一下:

# 信息性状态码
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: ('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

# 客户端错误状态码
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',),

# 服务端错误状态码
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')
6.文件上传

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

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

返回的结果大家可以在自己电脑上看。

7.Cookies

前面我们使用urllib处理过Cookies,写法比较复杂,而有了requests,获取和设置Cookies只需一步即可完成。

import requests
r = requests.get("http://tieba.baidu.com/f?ie=utf-8&kw=%E6%B9%96%E5%8C%97%E7%BB%8F%E6%B5%8E%E5%AD%A6%E9%99%A2")
print(r.cookies)
for key, value in r.cookies.items():
    print(key + '=' + value)

运行结果如下:

<RequestsCookieJar[<Cookie BAIDUID=691FAAA9A1B2BCC389C3803DE3F3A7DE:FG=1 for .baidu.com/>, <Cookie TIEBA_USERTYPE=3fad14137434bb1707615468 for .tieba.baidu.com/>]>
BAIDUID=691FAAA9A1B2BCC389C3803DE3F3A7DE:FG=1
TIEBA_USERTYPE=3fad14137434bb1707615468

这里我们首先调用cookies属性即可成功得到Cookies,可以发现它是RequestCookieJar类型。然后用items()方法将其转化为元组组成的列表,遍历输出每一个Cookie的名称和值,实现Cookie的遍历解析。
当然我们也可以将自己登陆后的cookies来维持登录状态,下面还是用知乎为例

import requests
headers = {
    'Cookie': '_zap=fb088aab-4271-4702-9f79-a83cd3b241b1; _xsrf=21713a2f-9a52-4c69-b5a0-cbc42a04b641; d_c0="AIAi3k8pEhCPTtIPkdiPzE_HPvUWm1JHut0=|1568876696"; tgw_l7_route=4860b599c6644634a0abcd4d10d37251; capsion_ticket="2|1:0|10:1568881198|14:capsion_ticket|44:ZDAzNjlmNmE3NTBhNDQyNDllNjUwZTY2NjNhMzEzZGQ=|79ba5fb5fbee8187a4f17d962e1fc8e313ae9ce3e3574857ad7c23df7bf5c00d"; l_n_c=1; r_cap_id="MzY2MmE1OWQ1ZDkwNDU3MTg0OWFlYzA3NGE0YzQ1MTg=|1568881210|22639adc0478eb7daaf98a39b322fdde3c4b886a"; cap_id="ZmZjYTY2YTZiMzgyNDEwNjgxYWQzNzQxYzgwMmNjMzM=|1568881210|d0f484488bf9ff8393b986c989b0ad9431b781eb"; l_cap_id="NWY5YzgzZWRkOTNlNDJlNmEwZWE2NTQ5MGNkYzQ0YjE=|1568881210|c8fc82e6624979ff0aa88fdd0458a9023b19df2a"; n_c=1; z_c0=Mi4xNDU1cEJnQUFBQUFBZ0NMZVR5a1NFQmNBQUFCaEFsVk5RWWh3WGdCdEd1SzgyYTJCV0RCYTNTN3ZsSXRJSG9PRFVB|1568881217|0f2d335543b8478a74b018564a8d27b7bf914f3b; tst=r',
    'Host': 'www.zhihu.com',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
}
r = requests.get('https://www.zhihu.com', headers=headers)
print(r.text)

这样我们就实现了用cookies保持登录状态,这里的cookies换成自己的试试:
在这里插入图片描述

8.会话维持

在requests中,如果直接利用get()或post()等方法的确可以做到模拟网页的请求,但是这实际上是相当于不同的会话,也就是说相当于你用了两个浏览器打开了不同的页面。
设想这样一个场景,第一个请求利用post()方法登录了某个网站,第二次想获取成功登录后的自己的个人信息,你又用了一次get()方法去请求个人信息页面。实际上,这相当于打开了两个浏览器,是两个完全不相关的会话,能成功获取个人信息吗?那当然不能。其实解决这个问题的主要方法就是维持同一个会话,也就是相当于打开一个新的浏览器选项卡而不是新开一个浏览器。但是我又不想每次设置cookies,那该怎么办呢?这时候就有了新的利器——Session对象。
这里我们请求了一个测试网址http://httpbin.org/cookies/set/number/123456789。请求这个网址时,可以设置一个cookie,名称叫作number,内容是123456789,随后又请求了http://httpbin.org/cookies,此网址可以获取当前的Cookies。

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

我们希望获取到cookies,返回的结果:

{
  "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)

返回结果是:

{
  "cookies": {
    "number": "123456789"
  }
}

成功获取!这下能体会到同一个会话和不同会话的区别了吧!

所以,利用Session,可以做到模拟同一个会话而不用担心Cookies的问题。它通常用于模拟登录成功之后再进行下一步的操作。

Session在平常用得非常广泛,可以用于模拟在一个浏览器中打开同一站点的不同页面。

9.SSL证书验证

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

前面我们提到过,12306的证书没有被官方CA机构信任,会出现证书验证错误的结果。我们现在访问它,都可以看到一个证书问题的页面。
我们需要修改它的verify参数就正常了。

import requests

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

在这里插入图片描述
但它会警告我们让我们给它指定证书,我们也可以忽略。我们也可以上传一个本地证书,我下面给出一个样例格式:

import requests

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

当然,上面的代码是演示实例,我们需要有crt和key文件,并且指定它们的路径。注意,本地私有证书的key必须是解密状态,加密状态的key是不支持的。后面有具体的例子我再来给大家讲解。

10.代理设置

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

那么,为了防止这种情况发生,我们需要设置代理来解决这个问题,这就需要用到proxies参数。可以用这样的方式设置:

import requests

proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}

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

这一块内容我们后面具体实践用到我在详细讲解,而且现在大多用的是那个API付费接口的代理,嵌入比较简单技术性要求不是很高,大家了解就行啦。最后在和大家提下超时设置,前面urllib也讲过了,实际差不多。

超时设置

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

import requests

r = requests.get("https://www.taobao.com", timeout = 1)
print(r.status_code)

返回200表示请求正常。实际上,请求分为两个阶段,即连接(connect)和读取(read)。

上面设置的timeout将用作连接和读取这二者的timeout总和。

如果要分别指定,就可以传入一个元组:

r = requests.get('https://www.taobao.com', timeout=(5,11, 30))

如果想永久等待,可以直接将timeout设置为None,或者不设置直接留空,因为默认是None。这样的话,如果服务器还在运行,但是响应特别慢,那就慢慢等吧,它永远不会返回超时错误的。其用法如下:

r = requests.get('https://www.taobao.com', timeout=None)
#r = requests.get('https://www.taobao.com')

当我们把这些大致了解,基本的request库用法也差不多了,剩下如果还有什么问题可以去官网查看。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用OpenCV进行五边形和人形的图像区分。下面是一个简单的示例代码,用于检测并标记图像中的五边形和人形。 ```python import cv2 import numpy as np # 读取图像 image = cv2.imread('image.jpg') # 将图像转换为灰度图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 使用Canny边缘检测算法检测边缘 edges = cv2.Canny(gray, 50, 150) # 在边缘图像上查找轮廓 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for contour in contours: # 计算轮廓的近似多边形 approx = cv2.approxPolyDP(contour, 0.01 * cv2.arcLength(contour, True), True) # 根据近似多边形的顶点数量进行判断 if len(approx) == 5: # 绘制五边形轮廓 cv2.drawContours(image, [approx], 0, (0, 255, 0), 2) cv2.putText(image, 'Pentagon', (approx.ravel()[0], approx.ravel()[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) elif len(approx) > 5: # 绘制人形轮廓 cv2.drawContours(image, [approx], 0, (0, 0, 255), 2) cv2.putText(image, 'Person', (approx.ravel()[0], approx.ravel()[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) # 显示结果图像 cv2.imshow('Image', image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在代码中,首先读取图像并将其转换为灰度图像。然后使用Canny边缘检测算法获取图像的边缘。接下来使用`cv2.findContours()`函数查找边缘图像上的轮廓。 对于每个轮廓,使用`cv2.approxPolyDP()`函数计算轮廓的近似多边形。根据近似多边形的顶点数量,判断是五边形还是人形,并在原始图像上绘制相应的轮廓和文字标签。 最后,显示结果图像并等待按键关闭窗口。 请注意,此示例仅用于简单的五边形和人形区分,对于复杂的形状可能不适用。您可能需要根据特定需求进行调整和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值