爬虫生活不易 我用python@IT·互联网

Python网络爬虫(五)- Requests和Beautifu

2017-08-11  本文已影响2192人  一只写程序的猿

目录:

1.简介

Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。

2.安装

pip install requests
easy_install requests

3.基本请求方式

requests为爬虫开发者们提供了8种基本的请求方式,由于在web开发过程中,大家发现对于服务器数据的处理方式没有一开始制定标准时设计的那么复杂,所以一般情况下都简化成了get/post两种常见的请求方式

req = requests.request(method,url, **kw)
req = requests.post(url, **kw)
req = requests.get(url, **kw)
req = requests.delete(url, **kw)
req = requests.put(url, **kw)
req = requests.head(url, **kw)
req = requests.options(url, **kw)
req = requests.patch(url, **kw)

1.基本GET请求

#python开发人员常用的测试地址 http://httpbin.org/gets
r = requests.get("http://httpbin.org/get")
import requests
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print r.url

运行结果:

http://httpbin.org/get?key2=value2&key1=value1

写一个JSON文件命名为a.json

["foo", "bar", {
 "foo": "bar"
}]

利用如下程序请求并解析

import requests
r = requests.get("a.json")
print r.text
print r.json()

运行结果如下,其中一个是直接输出内容,另外一个方法是利用 json() >方法解析

["foo", "bar", {
"foo": "bar"
}]
[u'foo', u'bar', {u'foo': u'bar'}]
r = requests.get('https://github.com/timeline.json', stream=True)
r.raw
<requests.packages.urllib3.response.HTTPResponse object at >0x101194810>
r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'

这样就获取了网页原始套接字内容。

import requests
payload = {'key1': 'value1', 'key2': 'value2'}
headers = {'content-type': 'application/json'}
r = requests.get("http://httpbin.org/get", params=payload, headers=headers)
print r.url

2.基本POST请求

import requests
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http://httpbin.org/post", data=payload)
print r.text

运行结果:

{
 "args": {}, 
"data": "", 
"files": {}, 
 "form": {
   "key1": "value1", 
   "key2": "value2"
 }, 
 "headers": {
   "Accept": "*/*", 
   "Accept-Encoding": "gzip, deflate", 
   "Content-Length": "23", 
   "Content-Type": "application/x-www-form-urlencoded", 
   "Host": "httpbin.org", 
   "User-Agent": "python-requests/2.9.1"
 }, 
 "json": null, 
 "url": "http://httpbin.org/post"
}
import json
import requests
url = 'http://httpbin.org/post'
payload = {'some': 'data'}
r = requests.post(url, data=json.dumps(payload))
print r.text

运行结果:

{
 "args": {}, 
 "data": "{\"some\": \"data\"}", 
 "files": {}, 
 "form": {}, 
 "headers": {
   "Accept": "*/*", 
   "Accept-Encoding": "gzip, deflate", 
   "Content-Length": "16", 
   "Host": "httpbin.org", 
   "User-Agent": "python-requests/2.9.1"
 }, 
 "json": {
   "some": "data"
 },  
 "url": "http://httpbin.org/post"
}

通过上述方法,我们可以POST JSON格式的数据

新建一个 a.txt 的文件,内容写上 Hello World!

import requests
url = 'http://httpbin.org/post'
files = {'file': open('test.txt', 'rb')}
r = requests.post(url, files=files)
print r.text

运行结果:

{
 "args": {}, 
 "data": "", 
 "files": {
   "file": "Hello World!"
 }, 
 "form": {}, 
 "headers": {
   "Accept": "*/*", 
   "Accept-Encoding": "gzip, deflate", 
   "Content-Length": "156", 
   "Content-Type": "multipart/form-data; >boundary=7d8eb5ff99a04c11bb3e862ce78d7000", 
   "Host": "httpbin.org", 
   "User-Agent": "python-requests/2.9.1"
 }, 
 "json": null, 
 "url": "http://httpbin.org/post"
}

这样我们便成功完成了一个文件的上传。

with open('massive-body') as f:
    response = requests.post('http://some.url/streamed', data=f)
    print(response.text)

4.Cookies

import requests

response = requests.get("http://www.baidu.com/")

# 返回CookieJar对象:
cookiejar = response.cookies

#将CookieJar转为字典:
cookiedict = requests.utils.dict_from_cookiejar(cookiejar)

print cookiejar

print cookiedict

5.超时配置

requests.get('http://github.com', timeout=0.001)

注:timeout 仅对连接过程有效,与响应体的下载无关。

6.会话对象

在以上的请求中,每次请求其实都相当于发起了一个新的请求。也就是相当于我们每个请求都用了不同的浏览器单独打开的效果。也就是它并不是指的一个会话,即使请求的是同一个网址。比如

import requests

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

结果:

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

在这里我们请求了两次,一次是设置 cookies,一次是获得 cookies
运行结果

{
 "cookies": {
   "sessioncookie": "123456789"
 }
}
import requests

s = requests.Session()
s.headers.update({'x-test': 'true'})
r = s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
print r.text

通过 s.headers.update 方法设置了 headers 的变量。两个变量都传送过>去了。
运行结果:

{
 "headers": {
   "Accept": "*/*", 
   "Accept-Encoding": "gzip, deflate", 
   "Host": "httpbin.org", 
   "User-Agent": "python-requests/2.9.1", 
   "X-Test": "true", 
   "X-Test2": "true"
 }
}
  • get方法传的headers 同样也是 x-test,它会覆盖掉全局的配置
{
 "headers": {
   "Accept": "*/*", 
   "Accept-Encoding": "gzip, deflate", 
  "Host": "httpbin.org", 
   "User-Agent": "python-requests/2.9.1", 
   "X-Test": "true"
 }
}
  • 如果不想要全局配置中的一个变量设置为 None 即可
r = s.get('http://httpbin.org/headers', headers={'x-test': None})

运行结果:

{
 "headers": {
  "Accept": "*/*", 
   "Accept-Encoding": "gzip, deflate", 
   "Host": "httpbin.org", 
   "User-Agent": "python-requests/2.9.1"
 }
}

7.SSL证书验证

现在随处可见 https 开头的网站,Requests可以为HTTPS请求验证SSL证书,就像web浏览器一样。要想检查某个主机的SSL证书,你可以使用 verify 参数,比如12306的证书无效。

测试如下:

import requests
r = requests.get('https://kyfw.12306.cn/otn/', verify=True)
print r.text

结果:

requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)
测试12306的证书无效
  • 如果我们想跳过刚才 12306 的证书验证,把 verify 设置为 False 即可
import requests

r = requests.get('https://kyfw.12306.cn/otn/', verify=False)
print r.text
在默认情况下 verify 是 True,所以如果需要的话,需要手动设置下这个变量。 源码中我们可以看到默认verify=False
# 1. 导入Python SSL处理模块
import ssl

# 2. 表示忽略未经核实的SSL证书认证
context = ssl._create_unverified_context()

8.代理

import requests

# 根据协议类型,选择不同的代理
proxies = {
 "https": "http://41.118.132.69:4433"
 "http": "http://41.118.132.69:4433"
}
r = requests.post("http://httpbin.org/post", proxies=proxies)
print r.text
#私密代理
import requests

# 如果代理需要使用HTTP Basic Auth,可以使用下面这种格式:
proxy = { "http": "mr_mao_hacker:sffqry9r@61.158.163.130:16816" }

response = requests.get("http://www.baidu.com", proxies = proxy)

print response.text
import requests

auth=('test', '123456')

response = requests.get('http://192.168.199.107', auth = auth)

print response.text
export HTTP_PROXY="http://10.10.1.10:3128"
export HTTPS_PROXY="http://10.10.1.10:1080"

通过以上方式,可以方便地设置代理。

5.程序中的使用

安装好request模块之后,在程序中就可以通过import引入并且使用了

# -*- coding:utf-8 -*-
# 引入requests模块
import requests

# 发送请求,得到服务器返回的响应对象,通过encoding设置响应中数据的编码
response = requests.get("http://www.sojson.com/open/api/weather/json.shtml?city=%E9%83%91%E5%B7%9E")
response.encoding="utf-8"

# 通过text打印响应中的文本数据
print(response.text)

结果:

{"message":"Success !",
"status":200,"city":"郑州","count":26,
"data":{"shidu":"74%","pm25":71.0,"pm10":145.0,"quality":"良","wendu":"31",
"ganmao":"极少数敏感人群应减少户外活动",
"yesterday":{"date":"10日星期四","sunrise":"05:41","high":"高温 37.0℃",
"low":"低温 25.0℃","sunset":"19:20","aqi":141.0,"fx":"西风","fl":"<3
级","type":"晴","notice":"lovely sunshine,尽情享受阳光的温暖吧"},
"forecast":[{"date":"11日星期五","sunrise":"05:42","high":"高温 37.0℃",
"low":"低温 25.0℃","sunset":"19:19","aqi":100.0,"fx":"南风",
"fl":"<3级","type":"晴","notice":"天气干燥,请适当增加室内湿度"},
{"date":"12日星期六","sunrise":"05:42","high":"高温 31.0℃","low":"低温 
24.0℃","sunset":"19:18","aqi":55.0,"fx":"东风","fl":"<3级","type":"阵雨",
"notice":"突如其来的雨,总叫让人措手不及"},{"date":"13日星期日",
"sunrise":"05:43","high":"高温 30.0℃","low":"低温 24.0℃",
"sunset":"19:17","aqi":60.0,"fx":"北风","fl":"<3级","type":"阵雨","notice":"突如其来的雨,总叫让人措手不及"},
{"date":"14日星期一","sunrise":"05:44","high":"高温 33.0℃",
"low":"低温 24.0℃","sunset":"19:16","aqi":62.0,"fx":"东北风","fl":"<3级",
"type":"晴","notice":"lovely sunshine,尽情享受阳光的温暖吧"},
{"date":"15日星期二","sunrise":"05:45","high":"高温 35.0℃",
"low":"低温 24.0℃","sunset":"19:14","aqi":65.0,"fx":"南风","fl":"<3级",
"type":"晴","notice":"天气干燥,请适当增加室内湿度"}]}}

先获取图片链接地址

# -*- coding:utf-8 -*-
import requests,re,urllib,urllib2


#定义引擎函数模块
def getImg(url):
    content = load_url(url)
    #数据获取完成,定义正则表达式,筛选数据
    reg = re.compile('"thumbURL":\s*"(.*?)"', re.S)
    data_list = data_filter(content,reg)
    #保存数据
    for index,data_url in enumerate(data_list):
        sava_data(data_url,"./images/" + str(index) + ".jpg")


#定义爬取数据的函数
def load_url(url):
    """
    作用:爬取指定url地址中的数据
    :param url: 指定的url地址
    :return: 所有爬取到的数据
    """
    print('开始爬取图片')
    my_headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36',
    }
    response = requests.get(url,headers=my_headers,verify=False)
    response.encoding = 'UTF-8'
    content = response.text
    print('数据爬取完成')
    return content

#定义筛选数据的函数
def data_filter(data,reg):
    """
    作用:进行数据按照指定描述的正则筛选
    :param data: 所有数据
    :param reg: 正则表达式
    :return: 返回筛选到的数据列表
    """
    print('---开始筛选数据')
    data_list = reg.findall(data)
    print('筛选数据完成')
    return data_list


#定义保存数据的函数
def sava_data(url_content,file_name):
    """
    作用:保存数据
    :param url_content:需要保存的数据
    :param file_name: 文件名称
    :return:
    """
    print('开始保存数据')
    try:
        urllib.urlretrieve(url_content, file_name)

        #另外一种保存方式
        # my_headers = {
        #     'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36',
        # }
        # print (url_content)
        # content = requests.get(url_content, headers=my_headers).content
        # with open(file_name, "wb") as f:
        #     f.write(content)
        print('图片下载成功')
    except Exception as result:
        print('图片下载失败'+str(result))
    print('数据保存完成')

#定义主程序入口
if __name__ == '__main__':
    #定义获取各种需要的参数数据
    url = 'https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%E4%BD%A0%E7%9A%84%E5%90%8D%E5%AD%97&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&word=%E4%BD%A0%E7%9A%84%E5%90%8D%E5%AD%97&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&pn=30&rn=30&gsm=1e&1502454817018='
    #调用引擎对象,执行爬虫
    getImg(url)

结果:

你的名字
写到最后说些题外话,今天爬取一个网站的时候还发生了一件好玩的事,网站的反爬机制导致爬取的数据只是一个html网页,看到了页面上的话,我想起了一句话,对于爬虫工程师来说每天都是不停地和对方的反爬工程师斗智斗勇。 那么问题来了,到底什么是世界上最牛逼的语言

4.BeautifulSoup4

1.Beautiful Soup的简介

Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:

  • Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
  • Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
  • Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。

2. Beautiful Soup 安装

Beautiful Soup 3 目前已经停止开发,推荐在现在的项目中使用Beautiful Soup 4,不过它已经被移植到BS4了,也就是说导入时我们需要 import bs4 。所以这里我们用的版本是 Beautiful Soup 4.3.2 (简称BS4),另外据说 BS4 对 Python3 的支持不够好,不过我用的是 Python2.7.7,如果有小伙伴用的是 Python3 版本,可以考虑下载 BS3 版本。

easy_install beautifulsoup4
pip install beautifulsoup4
由于我的是python2和python3共存,所以安装时需加上python版本安装
easy_install html5lib
pip install html5lib

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更加强大,速度更快,推荐安装。

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

Beautiful Soup 4.4.0 文档官方文档

find_all( name , attrs , recursive , string , **kwargs )
soup.find_all("a")
soup("a")
tag.p.a.get_text()

参考文档:Requests官方文档崔庆才老师的个人博客Beautiful Soup 4.4.0 文档 (中文文档)

上一篇下一篇

猜你喜欢

热点阅读