Python之网络请求

一、爬虫简介

1、爬虫的实际例子

(1)搜索引擎(百度、谷歌、360搜索等)。
(2)伯乐在线。
(3)惠惠购物助手。
(4)数据分析与研究(数据冰山知乎专栏)。
(5)抢票软件等。

2、什么是网络爬虫

(1)通俗理解:爬虫是一个模拟人类请求网站行为的程序。可以自动请求网页、并数据抓取下来,然后使用一定的规则提取有价值的数据

(2)专业介绍:百度百科

3、通用爬虫和聚焦爬虫

(1)通用爬虫:通用爬虫是搜索引擎抓取系统(百度、谷歌、搜狗等)的重要组成部分。主要是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。

(2)聚焦爬虫:是面向特定需求的一种网络爬虫程序,他与通用爬虫的区别在于:聚焦爬虫在实施网页抓取的时候会对内容进行筛选和处理,尽量保证只抓取与需求相关的网页信息。

4、为什么用Python写爬虫程序

(1)PHP:PHP是世界是最好的语言,但他天生不是做这个的,而且对多线程、异步支持不是很好,并发处理能力弱。爬虫是工具性程序,对速度和效率要求比较高。

(2)Java:生态圈很完善,是Python爬虫最大的竞争对手。但是Java语言本身很笨重,代码量很大。重构成本比较高,任何修改会导致代码大量改动。爬虫经常要修改采集代码。

(3)C/C++:运行效率是无敌的。但是学习和开发成本高。写个小爬虫程序可能要大半天时间。

(4)Python:语法优美、代码简洁、开发效率高、支持的模块多。相关的HTTP请求模块和HTML解析模块非常丰富。还有Scrapy和Scrapy-redis框架让我们开发爬虫变得异常简单。

5、准备工具

(1)Python3.6开发环境
(2)Pycharm 2017 professional版
(3)虚拟环境。`virtualenv/virtualenvwrapper

二、http协议和Chrome浏览器

1、什么是http和https协议

HTTP协议:全称是HyperText Transfer Protocol,中文意思是超文本传输协议,是一种发布和接收HTML页面的方法。服务器端口号是80端口。 HTTPS协议:是HTTP协议的加密版本,在HTTP下加入了SSL层。服务器端口号是443端口。

2、在浏览器中发送一个http请求的过程

(1)当用户在浏览器的地址栏中输入一个URL并按回车键之后,浏览器会向HTTP服务器发送HTTP请求。HTTP请求主要分为“Get”和“Post”两种方法

(2)当我们在浏览器输入URL http://www.baidu.com 的时候,浏览器发送一个Request请求去获取 http://www.baidu.com 的html文件,服务器把Response文件对象发送回给浏览器

(3)浏览器分析Response中的 HTML,发现其中引用了很多其他文件,比如Images文件,CSS文件,JS文件。 浏览器会自动再次发送Request去获取图片,CSS文件,或者JS文件

(4)当所有的文件都下载成功后,网页会根据HTML语法结构,完整的显示出来了

3、url详解

URL是Uniform Resource Locator的简写,统一资源定位符。 一个URL由以下几部分组成:

例如:scheme://host:port/path/?query-string=xxx#anchor

  • scheme:代表的是访问的协议,一般为http或者https以及ftp等
  • host:主机名,域名,比如www.baidu.com
  • port:端口号。当你访问一个网站的时候,浏览器默认使用80端口
  • path:查找路径。比如:www.jianshu.com/trending/now,后面的trending/now就是path
  • query-string:查询字符串,比如:www.baidu.com/s?wd=python,后面的wd=python就是查询字符串
  • anchor:锚点,后台一般不用管,前端用来做页面定位的

在浏览器中请求一个url,浏览器会对这个url进行一个编码。除英文字母,数字和部分符号外,其他的全部使用百分号+十六进制码值进行编码。

4、常用的请求方法

在Http协议中,定义了八种请求方法。这里介绍两种常用的请求方法,分别是get请求和post请求

(1)get请求:一般情况下,只从服务器获取数据下来,并不会对服务器资源产生任何影响的时候会使用get请求

(2)post请求:向服务器发送数据(登录)、上传文件等,会对服务器资源产生影响的时候会使用post请求。 以上是在网站开发中常用的两种方法。并且一般情况下都会遵循使用的原则。但是有的网站和服务器为了做反爬虫机制,也经常会不按常理出牌,有可能一个应该使用get方法的请求就一定要改成post请求,这个要视情况而定

5、请求头常见参数

在http协议中,向服务器发送一个请求,数据分为三部分,第一个是把数据放在url中,第二个是把数据放在body中(在post请求中),第三个就是把数据放在head中。这里介绍在网络爬虫中经常会用到的一些请求头参数:

(1)User-Agent:浏览器名称。这个在网络爬虫中经常会被使用到。请求一个网页的时候,服务器通过这个参数就可以知道这个请求是由哪种浏览器发送的。如果我们是通过爬虫发送请求,那么我们的User-Agent就是Python,这对于那些有反爬虫机制的网站来说,可以轻易的判断你这个请求是爬虫。因此我们要经常设置这个值为一些浏览器的值,来伪装我们的爬虫

(2)Referer:表明当前这个请求是从哪个url过来的。这个一般也可以用来做反爬虫技术。如果不是从指定页面过来的,那么就不做相关的响应

(3)Cookie:http协议是无状态的。也就是同一个人发送了两次请求,服务器没有能力知道这两个请求是否来自同一个人。因此这时候就用cookie来做标识。一般如果想要做登录后才能访问的网站,那么就需要发送cookie信息了

6、常见响应状态码

(1)200:请求正常,服务器正常的返回数据

(2)301:永久重定向。比如在访问www.jingdong.com的时候会重定向到www.jd.com

(3)302:临时重定向。比如在访问一个需要登录的页面的时候,而此时没有登录,那么就会重定向到登录页面

(4)400:请求的url在服务器上找不到。换句话说就是请求url错误

(5)403:服务器拒绝访问,权限不够

(6)500:服务器内部错误。可能是服务器出现bug了

三、urllib库

1、urllib库

urllib库是Python中一个最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据

2、urlopen函数

在Python3的urllib库中,所有和网络请求相关的方法,都被集到urllib.request模块下面了,以先来看下urlopen函数基本的使用:

from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read())

实际上,使用浏览器访问百度,右键查看源代码。你会发现,跟我们刚才打印出来的数据是一模一样的。也就是说,上面的三行代码就已经帮我们把百度的首页的全部代码爬下来了。一个基本的url请求对应的python代码真的非常简单

以下对urlopen函数的进行详细讲解:
(1)url:请求的url
(2)data:请求的data,如果设置了这个值,那么将变成post请求
(3)返回值:返回值是一个http.client.HTTPResponse对象,这个对象是一个类文件句柄对象。有read(size)、readline、readlines以及getcode等方法

3、urlretrieve函数

这个函数可以方便的将网页上的一个文件保存到本地。以下代码可以非常方便的将百度的首页下载到本地:

from urllib import request

# 将百度首页下载到本地
request.urlretrieve('http://www.baidu.com','baidu.html')

# 下载图片
request.urlretrieve('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533566044817&di=7692eeb3301d0433a8e0f8d73da19b0e&imgtype=0&src=http%3A%2F%2Fu.candou.com%2F2017%2F0613%2F1497342507815.jpg'
    ,'luban.jpg')

4、urlencode函数

用浏览器发送请求的时候,如果url中包含了中文或者其他特殊字符,那么浏览器会自动的给我们进行编码。而如果使用代码发送请求,那么就必须手动的进行编码,这时候就应该使用urlencode函数来实现。urlencode可以把字典数据转换为URL编码的数据。示例代码如下:

from urllib import parse
param = {'name':'张三','age':18,'greet':'Hello World'}
result = parse.urlencode(param)
print(result)

# 编码并请求
url = 'https://www.baidu.com/s?ie=UTF-8&'
param = {'wd':'刘德华'}
result = parse.urlencode(param)
result = url + result
ps = request.urlopen(result)
print(ps.read())

5、parse_qs函数

可以将经过编码后的url参数进行解码。示例代码如下:

from urllib import parse
param = {'name':'张三','age':18,'greet':'Hello World'}
result = parse.urlencode(param);
qs = parse.parse_qs(result)
print(qs)

6、urlparse和urlsplit

有时候拿到一个url,想要对这个url中的各个组成部分进行分割,那么这时候就可以使用urlparse或者是urlsplit来进行分割

from urllib import request,parse

url = 'http://www.baidu.com/s?username=zhiliao'
result1 = parse.urlsplit(url)
result2 = parse.urlparse(url)
print(result1)
print(result2)
print('scheme:',result1.scheme)
print('netloc:',result1.netloc)
print('path',result1.path)
print('query',result1.query)

urlparse和urlsplit基本上是一模一样的。唯一不一样的地方是,urlparse里面多了一个params属性,而urlsplit没有这个params属性。比如有一个url为:url = ‘http://www.baidu.com/s;hello?wd=python&username=abc#1‘,
那么urlparse可以获取到hello,而urlsplit不可以获取到。url中的params也用得比较少

7、request.Request类

如果想要在请求的时候增加一些请求头,那么就必须使用request.Request类来实现。比如要增加一个User-Agent

from urllib import request

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}
req = request.Request("http://www.baidu.com/",headers=headers)
resp = request.urlopen(req)
print(resp.read())

8、ProxyHandler处理器(代理设置)

很多网站会检测某一段时间某个IP的访问次数(通过流量统计,系统日志等),如果访问次数多的不像正常人,它会禁止这个IP的访问。
所以我们可以设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。
urllib中通过ProxyHandler来设置使用代理服务器

"""
# 没有使用代理
url = 'http://httpbin.org/ip'
resp = request.urlopen(url)
print(resp.read())
"""

# 使用代理

url = 'http://httpbin.org/ip'
# 1、使用ProxyHandler,传入代理构建一个handler
handler = request.ProxyHandler({"http":"115.46.73.180:8123"})
# 2、使用上面创建的handler构建一个opener
opener = request.build_opener(handler)
# 3、使用opener去发送一个请求
resp = opener.open(url)
print(resp.read())

常用的代理有:
(1)西刺免费代理IP:http://www.xicidaili.com/
(2)快代理:http://www.kuaidaili.com/
(3)代理云:http://www.dailiyun.com/

9、什么是cookie

在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。

cookie格式:

Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

参数意义:

  • NAME:cookie的名字
  • VALUE:cookie的值
  • Expires:cookie的过期时间
  • Path:cookie作用的路径
  • Domain:cookie作用的域名
  • SECURE:是否只在https协议下起作用

10、使用cookielib库和HTTPCookieProcessor模拟登录

Cookie 是指网站服务器为了辨别用户身份和进行Session跟踪,而储存在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话。
这里以人人网为例。人人网中,要访问某个人的主页,必须先登录才能访问,登录说白了就是要有cookie信息。那么如果我们想要用代码的方式访问,就必须要有正确的cookie信息才能访问。解决方案有两种,第一种是使用浏览器访问,然后将cookie信息复制下来,放到headers中

from urllib import request

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
    'Cookie': 'anonymid=jacdwz2x-8bjldx; depovince=GW; _r01_=1; _ga=GA1.2.1455063316.1511436360; _gid=GA1.2.862627163.1511436360; wp=1; JSESSIONID=abczwY8ecd4xz8RJcyP-v; jebecookies=d4497791-9d41-4269-9e2b-3858d4989785|||||; ick_login=884e75d4-f361-4cff-94bb-81fe6c42b220; _de=EA5778F44555C091303554EBBEB4676C696BF75400CE19CC; p=61a3c7d0d4b2d1e991095353f83fa2141; first_login_flag=1; [email protected]; ln_hurl=http://hdn.xnimg.cn/photos/hdn121/20170428/1700/main_nhiB_aebd0000854a1986.jpg; t=3dd84a3117737e819dd2c32f1cdb91d01; societyguester=3dd84a3117737e819dd2c32f1cdb91d01; id=443362311; xnsid=169efdc0; loginfrom=syshome; ch_id=10016; jebe_key=9c062f5a-4335-4a91-bf7a-970f8b86a64e%7Ca022c303305d1b2ab6b5089643e4b5de%7C1511449232839%7C1; wp_fold=0'
}

url = 'http://www.renren.com/880151247/profile'

req = request.Request(url,headers=headers)
resp = request.urlopen(req)
with open('renren.html','w') as fp:
    fp.write(resp.read().decode('utf-8'))

但是每次在访问需要cookie的页面都要从浏览器中复制cookie比较麻烦。在Python处理Cookie,一般是通过http.cookiejar模块和urllib模块的HTTPCookieProcessor处理器类一起使用。http.cookiejar模块主要作用是提供用于存储cookie的对象。而HTTPCookieProcessor处理器主要作用是处理这些cookie对象,并构建handler对象。

http.cookiejar模块:

该模块主要的类有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。这四个类的作用分别如下:

(1)CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。

(2)FileCookieJar (filename,delayload=None,policy=None):从CookieJar派生而来,用来创建FileCookieJar实例,检索cookie信息并将cookie存储到文件中。filename是存储cookie的文件名。delayload为True时支持延迟访问访问文件,即只有在需要时才读取文件或在文件中存储数据。

(3)MozillaCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与Mozilla浏览器 cookies.txt兼容的FileCookieJar实例

(4)LWPCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与libwww-perl标准的 Set-Cookie3 文件格式兼容的FileCookieJar实例

11、登录人人网

利用http.cookiejar和request.HTTPCookieProcessor登录人人网


# 使用cookieJar访问人人网

from urllib import request
from http.cookiejar import CookieJar
from urllib import parse

headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',

}
def get_opener():
    # 1、登陆
    # 1.1 创建一个cookiejar对象
    cookiejar = CookieJar()
    # 1.2 使用cookiejar创建一个HTTPCookieProcess对象
    handler = request.HTTPCookieProcessor(cookiejar)
    # 1.3 使用上一步创建的handler创建一个opener
    opener = request.build_opener(handler)
    return opener

def login_renren(opener):
    # 1.4 使用opener发送登陆请求(包含人人网的邮箱密码)
    data = {
        'email':"[email protected]",
        'password':"pythonspider"
    }
    login_url = "http://www.renren.com/PLogin.do"
    req = request.Request(url=login_url,data=parse.urlencode(data).encode('utf-8'),headers=headers)
    opener.open(req)


def visit_profile(opener):
    # 2、访问个人主页
    depeng_url = "http://www.renren.com/880151247/profile"
    req = request.Request(depeng_url,headers=headers)
    # 获取个人主页的页面的时候,不要新建一个opener
    # 而是应该使用之前的opener,因为之前的那个opener
    # 包含了登陆的cookie
    resp = opener.open(req)
    with open('renren.html','w',encoding='utf-8') as fp:
        fp.write(resp.read().decode('utf-8'))


if __name__ == '__main__':
    opener = get_opener()
    login_renren(opener)
    visit_profile(opener)

12、保存cookie到本地

保存cookie到本地,可以使用cookiejar的save方法,并且需要指定一个文件名

# 将cookie信息保存到本地文件
from urllib import request
from http.cookiejar import MozillaCookieJar

# # 指定保存到cookie.txt文件中
cookiejar = MozillaCookieJar('cookie.txt')

handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)

resp = opener.open('http://www.baidu.com')

# ignore_discard=True 将过期的cookie信息也保存
cookiejar.save(ignore_discard=True)

从本地文件中获取cookie信息:

from urllib import request
from http.cookiejar import MozillaCookieJar
# 从本地文件中读取cookie信息
cookiejar2 = MozillaCookieJar('cookie.txt')
# 导入cookie(包含过期的)
cookiejar2.load(ignore_discard=True)
handler2 = request.HTTPCookieProcessor(cookiejar2)
opener2 = request.build_opener(handler2)
# 循环打印cookie信息
for cookie in cookiejar2:
    print(cookie)

四、request库

你可能感兴趣的:(Python,Python网络请求,urllib库,http协议,request库)