爬虫笔记1-抓取

2018-12-25  本文已影响0人  三流之路

request 库

requests 模块非自带,需要单独下载。用于从 Web 抓取文件。

Response 属性

>>> import requests
>>> res = requests.get('http://www.gutenberg.org/cache/epub/1112/pg1112.txt')
>>> type(res)
<class 'requests.models.Response'>
>>> res.status_code == requests.codes.ok
True
>>> len(res.text)
178981
>>> print(res.text[:250])
The Project Gutenberg EBook of Romeo and Juliet, by William Shakespeare

This eBook is for the use of anyone anywhere at no cost and with
almost no restrictions whatsoever.  You may copy it, give it away or
re-use it under the terms of the Proje
>>> res = requests.get('https://www.jianshu.com/u/de895f0d5942')
>>> res.status_code
403

get 方法返回一个 Response 对象,这个对象有如下属性:

属性 说明
r.status_code HTTP 请求的返回状态,200 表示连接成功,404 表示失败
r.text HTTP 响应内容的字符串形式,即 url 对应的页面内容
r.encoding 从 HTTP header 中猜测的响应内容编码方式
r.apparent_encoding 从内容中分析出的响应内容编码方式(备选编码方式)
r.content HTTP 响应内容的二进制形式

如果 Response 的 status_code 为 200,即 requests.codes.ok,表明请求下载成功。请求成功的话,下载的页面作为一个字符串存在 Response 的 text 里。

第二次去请求自己的简书页面,status_code 为 403,被服务器拒绝了。

编码

如果 r.text 为乱码,可以将 r.apparent_encoding 的值赋给 r.encoding。

连接异常

异常 说明
requests.ConnectionError 网络连接错误异常,如 DNS 查询失败、拒绝连接等
requests.HTTPError HTTP 错误异常
requests.URLRequired URL 缺失异常
requests.TooManyRedirects 超过最大重定向次数,产生重定向异常
requests.ConnectTimeout 连接远程服务器超时异常
requests.Timeout 请求 URL 超时,产生超时异常
r.raise_for_status() 如果不是 200,产生异常 requests.HTTPError

使用 raise_for_status() 来检查是否成功,成功继续向下执行,失败会抛出异常。

import requests

res = requests.get('http://inventwithpython.com/page_that_does_not_exist')
try:
    res.raise_for_status()
    res.encoding = r.apparent_encoding
except Exception as exc:
    print('There was a problem: %s' % (exc))

主要方法

主要有七个方法,这些方法的内部都是调用的 request 方法:

1. requests.request()

构造一个请求,支撑其它方法的基础方法。

requests.request(method, url, **kwargs)

    8. timeout:设定超时时间,单位秒

        ```
        >>> r = requests.request('GET', 'http://www.baidu.com', timeout=10)
        ```
        
    9. proxies:字典类型,设定访问代理服务器,可以增加登录认证

        ```
        >>> pxs = { 'http': 'http://user:pass@10.10.10.1:1234' 'https': 'https://10.10.10.1:4321' }

        >>> r = requests.request('GET', 'http://www.baidu.com', proxies=pxs)
        ```
        
    10. allow_redirects:True/False,默认为 True,重定向开关 
    11. stream:True/False,默认为 True,获取内容立即下载开关  
    12. verify:True/False,默认为 True,认证 SSL 证书开关 
    13. cert:本地 SSL 证书路径

### 2. requests.get()

获取 HTML 网页的主要方法,对应于 HTTP 的 GET。

```python
requests.get(url, params=None, **kwargs)
>>> kv = {'wd': 'Python'}
>>> r = requests.get("http://www.baidu.com/s", params = kv)
>>> r.status_code
200
>>> r.request.url
'http://www.baidu.com/s?wd=Python'

3. requests.head()

获取 HTML 网页头信息的方法,对应于 HTTP 的 HEAD。

requests.head(url, **kwargs)
>>> r = requests.head('http://httpbin.org/get')

>>> r.headers {'Content‐Length': '238', 'Access‐Control‐Allow‐Origin': '*', 'AccessControl‐Allow‐Credentials': 'true', 'Content‐Type': 'application/json', 'Server': 'nginx', 'Connection': 'keep‐alive', 'Date': 'Sat, 18 Feb 2017 12:07:44 GMT'}

>>> r.text ''

4. requests.post()

向 HTML 网页提交 POST 请求的方法,对应于 HTTP 的 POST。

requests.post(url, data=None, json=None, **kwargs)
>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.post('http://httpbin.org/post', data = payload)

>>> print(r.text)
{ ...

    "form": { 
        "key2": "value2",
        "key1": "value1" 
    },
}

向 URL POST 一个字典自动编码为 form(表单)。

>>> r = requests.post('http://httpbin.org/post', data = 'ABC')

>>> print(r.text) 
{ ...
    "data": "ABC"  
    "form": {}, 
}

向 URL POST 一个字符串自动编码为 data。

5. requests.put()

向 HTML 网页提交 PUT 请求的方法,对应于 HTTP 的 PUT。

requests.put(url, data=None, **kwargs)
>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.put('http://httpbin.org/put', data = payload)

>>> print(r.text) 
{ ...
    "form": { 
        "key2": "value2", 
        "key1": "value1" 
    },
}

6. requests.patch()

向 HTML 网页提交局部修改请求,对应于 HTTP 的 PATCH。

requests.patch(url, data=None, **kwargs)

patch 方法是局部更新,假设 url 有 20 组数据,修改了一组,patch 提交修改的这一组数据即可,而 put 必须把所有 20 个字段一并提交,未提交字段将被删除。所以 patch 方法可以节省网络带宽。

7. requests.delete()

向 HTML 页面提交删除请求,对应于 HTTP 的 DELETE。

requests.delete(url, **kwargs)

几个方法内部都是调用 request 方法,因为安全问题,一般不允许提交信息,主要使用 get 和 head 方法获取信息。

保存网页文件

为了保存网页的 Unicode 编码,文件必须以二进制模式写,即文件打开模式需要是 wb

写文件主要通过 Response 的 iter_content() 方法,参数表示要读取的二进制字节数。

import requests

res = requests.get('http://www.gutenberg.org/cache/epub/1112/pg1112.txt')
res.raise_for_status() # 不捕获异常,如果请求下载失败程序终止
playFile = open('RomeoAndJuliet.txt', 'wb')
# playFile.write(res.content) 写入所有内容
for chunk in res.iter_content(100000):
    playFile.write(chunk)
playFile.close()

Robots

全称 Robots Exclusion Standard,网络爬虫排除标准。

作用:网站告知网络爬虫哪些页面可以抓取,哪些不行。

形式:在网站根目录下的 robots.txt 文件。

例如京东的 robots 文件内容为:

User-agent: * 
Disallow: /?* 
Disallow: /pop/*.html 
Disallow: /pinpai/*.html?* 
User-agent: EtaoSpider 
Disallow: / 
User-agent: HuihuiSpider 
Disallow: / 
User-agent: GwdangSpider 
Disallow: / 
User-agent: WochachaSpider 
Disallow: /

其它的 Robots 协议文件

Robots 协议是建议但非约束性,网络爬虫可以不遵守,但存在法律风险,所以还是应该遵守。除非写小程序,只是访问几次,和人类行为类似时,且不用于商业用途,可以不遵守。

实例

1. 访问亚马逊中国的一个网页

>>> import requests
>>> r = requests.get('https://www.amazon.cn/dp/B07DXS2KFG')
>>> r.status_encoding
503

响应码是 503,被拒绝访问了

>>> r.text

可以看到有 For information about migrating to our APIs refer to our Marketplace APIs at ...抱歉,我们只是想确认一下当前访问者并非自动程序。为了达到最佳效果,请确保您浏览器上的 Cookie 已启用。 之类的文字。

一般一是通过 Robots 协议限制访问, 二是通过 API 判断请求者是否是浏览器,如果不是就拒绝。

看一下请求头

>>> r.request.headers
{'User-Agent': 'python-requests/2.19.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

其中 User-Agentpython-requests,而亚马逊拒绝了这种请求。

自定义请求头

>>> kv = {'user-agent':'Mozilla/5.0'}
>>> url = 'https://www.amazon.cn/dp/B07DXS2KFG'
>>> r = requests.get(url, headers = kv)
>>> r.status_code
200
>>> r.request.headers
{'user-agent': 'Mozilla/5.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

打印内容时有乱码,需要调整编码

>>> r.encoding
'ISO-8859-1'
>>> r.apparent_encoding
'utf-8'
>>> r.encoding = r.apparent_encoding
>>> r.text[2500:3500]
'ut type=hidden name="amzn" value="/E0+4zbLzrcBLVYh+4+P8Q==" /><input type=hidden name="amzn-r" value="&#047;dp&#047;B07DXS2KFG" />\n                            <div class="a-row a-spacing-large">\n                                <div class="a-box">\n                                    <div class="a-box-inner">\n                                        <h4>请输入您在这个图片中看到的字符:</h4>\n                                        <div class="a-row a-text-center">\n                                            <img src="https://images-na.ssl-images-amazon.com/captcha/ddwwidnf/Captcha_dnhmphvvcp.jpg">\n                                        </div>\n                                        <div class="a-row a-spacing-base">\n                                            <div class="a-row">\n                                                <div class="a-column a-span6">\n                                                    <label for="captchacharacters">输入字符</label>\n                                                </div>'

2. 下载图片

import requests
import os

# 要下载的网络图片地址
url = 'https://img13.360buyimg.com/n1/jfs/t1/2058/25/3461/212622/5b99b98cE56bd6510/24950384ea0cebad.jpg'
# 图片要保存的地址
root = '/Users/silas/Downloads/'
path = root + url.split('/')[-1] # 截取 url 后的文件名

# 确保文件夹存在
if not os.path.exists(root):
    os.mkdir(root)

# 文件不存在时再去下载
if not os.path.exists(path):
    res = requests.get(url)
    try:
        res.raise_for_status()
        with open(path, 'wb') as f:
            f.write(res.content) # 二进制内容写到文件中
            print('文件下载成功')
    except:
        print('爬取失败')
else:
    print('文件已存在')

Python网络爬虫与信息提取笔记

上一篇下一篇

猜你喜欢

热点阅读