第二节 http协议和Chrome抓包工具html
HTTP协议:全称是HyperText Transfer Protocol
,中文意思是超文本传输协议,是一种发布和接收HTML页面的方法。服务器端口号是80
端口。 HTTPS协议:是HTTP协议的加密版本,在HTTP下加入了SSL层。服务器端口号是443
端口。前端
URL
是Uniform Resource Locator
的简写,统一资源定位符。 一个URL
由如下几部分组成:python
scheme://host:port/path/?query-string=xxx#anchor
http
或者https
以及ftp
等。www.baidu.com
。www.jianshu.com/trending/now
,后面的trending/now
就是path
。www.baidu.com/s?wd=python
,后面的wd=python
就是查询字符串。在浏览器中请求一个url
,浏览器会对这个url进行一个编码。除英文字母,数字和部分符号外,其余的所有使用百分号+十六进制码值进行编码。git
在Http
协议中,定义了八种请求方法。这里介绍两种经常使用的请求方法,分别是get
请求和post
请求。github
get
请求:通常状况下,只从服务器获取数据下来,并不会对服务器资源产生任何影响的时候会使用get
请求。post
请求:向服务器发送数据(登陆)、上传文件等,会对服务器资源产生影响的时候会使用post
请求。 以上是在网站开发中经常使用的两种方法。而且通常状况下都会遵循使用的原则。可是有的网站和服务器为了作反爬虫机制,也常常会不按常理出牌,有可能一个应该使用get
方法的请求就必定要改为post
请求,这个要视状况而定。在http
协议中,向服务器发送一个请求,数据分为三部分,第一个是把数据放在url中,第二个是把数据放在body
中(在post
请求中),第三个就是把数据放在head
中。这里介绍在网络爬虫中常常会用到的一些请求头参数:web
User-Agent
:浏览器名称。这个在网络爬虫中常常会被使用到。请求一个网页的时候,服务器经过这个参数就能够知道这个请求是由哪一种浏览器发送的。若是咱们是经过爬虫发送请求,那么咱们的User-Agent
就是Python
,这对于那些有反爬虫机制的网站来讲,能够轻易的判断你这个请求是爬虫。所以咱们要常常设置这个值为一些浏览器的值,来假装咱们的爬虫。Referer
:代表当前这个请求是从哪一个url
过来的。这个通常也能够用来作反爬虫技术。若是不是从指定页面过来的,那么就不作相关的响应。Cookie
:http
协议是无状态的。也就是同一我的发送了两次请求,服务器没有能力知道这两个请求是否来自同一我的。所以这时候就用cookie
来作标识。通常若是想要作登陆后才能访问的网站,那么就须要发送cookie
信息了。200
:请求正常,服务器正常的返回数据。301
:永久重定向。好比在访问www.jingdong.com
的时候会重定向到www.jd.com
。302
:临时重定向。好比在访问一个须要登陆的页面的时候,而此时没有登陆,那么就会重定向到登陆页面。400
:请求的url
在服务器上找不到。换句话说就是请求url
错误。403
:服务器拒绝访问,权限不够。500
:服务器内部错误。多是服务器出现bug
了。Chrome
浏览器是一个很是亲近开发者的浏览器。能够方便的查看网络请求以及发送的参数。对着网页右键->检查
。而后就能够打开开发者选项。redis
Elements: 构成这个网页的源代码。chrome
Console:这个网页的控制台。json
Sources:组成这个网页的全部源文件。c#
Network:加载这个页面时,浏览器发送的全部请求。
第三节 urllib库
urllib
库是Python
中一个最基本的网络请求库。能够模拟浏览器的行为,向指定的服务器发送一个请求,并能够保存服务器返回的数据。
在Python3
的urllib
库中,全部和网络请求相关的方法,都被集到urllib.request
模块下面了,以先来看下urlopen
函数基本的使用:
from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read())
实际上,使用浏览器访问百度,右键查看源代码。你会发现,跟咱们刚才打印出来的数据是如出一辙的。也就是说,上面的三行代码就已经帮咱们把百度的首页的所有代码爬下来了。一个基本的url请求对应的python代码真的很是简单。 如下对urlopen
函数的进行详细讲解:
url
:请求的url。data
:请求的data
,若是设置了这个值,那么将变成post
请求。http.client.HTTPResponse
对象,这个对象是一个类文件句柄对象。有read(size)
、readline
、readlines
以及getcode
等方法。这个函数能够方便的将网页上的一个文件保存到本地。如下代码能够很是方便的将百度的首页下载到本地:
from urllib import request request.urlretrieve('http://www.baidu.com/','baidu.html')
urlencode函数:
用浏览器发送请求的时候,若是url中包含了中文或者其余特殊字符,那么浏览器会自动的给咱们进行编码。而若是使用代码发送请求,那么就必须手动的进行编码,这时候就应该使用urlencode
函数来实现。urlencode
能够把字典数据转换为URL
编码的数据。示例代码以下:
from urllib import parse data = {'name':'爬虫基础','greet':'hello world','age':100} qs = parse.urlencode(data) print(qs)
能够将通过编码后的url参数进行解码。示例代码以下:
from urllib import parse qs = "name=%E7%88%AC%E8%99%AB%E5%9F%BA%E7%A1%80&greet=hello+world&age=100" print(parse.parse_qs(qs))
urlparse和urlsplit:
有时候拿到一个url,想要对这个url中的各个组成部分进行分割,那么这时候就可使用urlparse
或者是urlsplit
来进行分割。示例代码以下:
from urllib import request,parse url = 'http://www.baidu.com/s?username=zhiliao' result = parse.urlsplit(url) # result = parse.urlparse(url) print('scheme:',result.scheme) print('netloc:',result.netloc) print('path:',result.path) print('query:',result.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
也用得比较少。
若是想要在请求的时候增长一些请求头,那么就必须使用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())
不少网站会检测某一段时间某个IP的访问次数(经过流量统计,系统日志等),若是访问次数多的不像正常人,它会禁止这个IP的访问。 因此咱们能够设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然能够换个IP继续爬取。 urllib中经过ProxyHandler来设置使用代理服务器,下面代码说明如何使用自定义opener来使用代理:
from urllib import request # 这个是没有使用代理的 # resp = request.urlopen('http://httpbin.org/get') # print(resp.read().decode("utf-8")) # 这个是使用了代理的 handler = request.ProxyHandler({"http":"218.66.161.88:31769"}) opener = request.build_opener(handler) req = request.Request("http://httpbin.org/ip") resp = opener.open(req) print(resp.read())
经常使用的代理有:
在网站中,http请求是无状态的。也就是说即便第一次和服务器链接后而且登陆成功后,第二次请求服务器依然不能知道当前请求是哪一个用户。cookie
的出现就是为了解决这个问题,第一次登陆后服务器返回一些数据(cookie)给浏览器,而后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie
数据自动的携带给服务器,服务器经过浏览器携带的数据就能判断当前用户是哪一个了。cookie
存储的数据量有限,不一样的浏览器有不一样的存储大小,但通常不超过4KB。所以使用cookie
只能存储一些小量的数据。
Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
参数意义:
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; ln_uact=970138074@qq.com;
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对象。
该模块主要的类有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。这四个类的做用分别以下:
利用http.cookiejar
和request.HTTPCookieProcessor
登陆人人网。相关示例代码以下:
from urllib import request,parse from http.cookiejar import CookieJar 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' } def get_opener(): cookiejar = CookieJar() handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) return opener def login_renren(opener): data = {"email": "970138074@qq.com", "password": "pythonspider"} data = parse.urlencode(data).encode('utf-8') login_url = "http://www.renren.com/PLogin.do" req = request.Request(login_url, headers=headers, data=data) opener.open(req) def visit_profile(opener): url = 'http://www.renren.com/880151247/profile' req = request.Request(url,headers=headers) resp = opener.open(req) with open('renren.html','w') as fp: fp.write(resp.read().decode("utf-8")) if __name__ == '__main__': opener = get_opener() login_renren(opener) visit_profile(opener)
保存cookie
到本地,可使用cookiejar
的save
方法,而且须要指定一个文件名:
from urllib import request from http.cookiejar import MozillaCookieJar cookiejar = MozillaCookieJar("cookie.txt") handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) 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://httpbin.org/cookies',headers=headers) resp = opener.open(req) print(resp.read()) cookiejar.save(ignore_discard=True,ignore_expires=True)
从本地加载cookie
,须要使用cookiejar
的load
方法,而且也须要指定方法:
from urllib import request from http.cookiejar import MozillaCookieJar cookiejar = MozillaCookieJar("cookie.txt") cookiejar.load(ignore_expires=True,ignore_discard=True) handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) 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://httpbin.org/cookies',headers=headers) resp = opener.open(req) print(resp.read())
虽然Python的标准库中 urllib模块已经包含了日常咱们使用的大多数功能,可是它的 API 使用起来让人感受不太好,而 Requests宣传是 “HTTP for Humans”,说明使用更简洁方便。
利用pip
能够很是方便的安装:
pip install requests
中文文档:http://docs.python-requests.org/zh_CN/latest/index.html
github地址:https://github.com/requests/requests
最简单的发送get
请求就是经过requests.get
来调用:
response = requests.get("http://www.baidu.com/")
添加headers和查询参数: 若是想添加 headers,能够传入headers参数来增长请求头中的headers信息。若是要将参数放在url中传递,能够利用 params 参数。相关示例代码以下:
import requests kw = {'wd':'中国'} headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} # params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不须要urlencode() response = requests.get("http://www.baidu.com/s", params = kw, headers = headers) # 查看响应内容,response.text 返回的是Unicode格式的数据 print(response.text) # 查看响应内容,response.content返回的字节流数据 print(response.content) # 查看完整url地址 print(response.url) # 查看响应头部字符编码 print(response.encoding) # 查看响应码 print(response.status_code)
注释:response.text和response.content的区别: 1.response.text:这是个str的数据类型,是requests库将response.content进行解码的字符串,解码须要制定一个编码方式,requests会根据本身的猜想来判断编码的方式。因此有时候可能会有猜想错误,就会致使解码产生乱码,这时候就应该使用response.content.decode('utf-8')进行手动解码。 2.response.content:这个是直接从网络上面抓取的数据。没有通过任何解码。因此是一个bytes类型。其实在硬盘上和网络上传输的字符串都是bytes类型。
最基本的POST请求可使用post
方法:
response = requests.post("http://www.baidu.com/",data=data)
传入data数据: 这时候就不要再使用urlencode
进行编码了,直接传入一个字典进去就能够了。好比请求拉勾网的数据的代码:
import requests url = "https://www.lagou.com/jobs/positionAjax.json?city=%E6%B7%B1%E5%9C%B3&needAddtionalResult=false&isSchoolJob=0" 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', 'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=' } data = { 'first': 'true', 'pn': 1, 'kd': 'python' } resp = requests.post(url,headers=headers,data=data) # 若是是json数据,直接能够调用json方法 print(resp.json())
注释:发送post请求很是简单,直接调用“requests.post”方法就好了。若是返回的是json数据,那么能够调用“response.json()”来将json字符串转换为字典或者列表。
使用requests
添加代理也很是简单,只要在请求的方法中(好比get
或者post
)传递proxies
参数就能够了。示例代码以下:
import requests url = "http://httpbin.org/get" 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', } proxy = { 'http': '171.14.209.180:27829' } resp = requests.get(url,headers=headers,proxies=proxy) with open('xx.html','w',encoding='utf-8') as fp: fp.write(resp.text)
注释:在请求方法中,传递“proxies”参数就能够了。
cookie:
若是在一个响应中包含了cookie
,那么能够利用cookies
属性拿到这个返回的cookie
值:
import requests url = "http://www.renren.com/PLogin.do" data = {"email":"970138074@qq.com",'password':"pythonspider"} resp = requests.get('http://www.baidu.com/') print(resp.cookies) print(resp.cookies.get_dict())
注释:若是想要在屡次请求中共享cookie,那么应该使用session。
以前使用urllib
库,是可使用opener
发送多个请求,多个请求之间是能够共享cookie
的。那么若是使用requests
,也要达到共享cookie
的目的,那么可使用requests
库给咱们提供的session
对象。注意,这里的session
不是web开发中的那个session,这个地方只是一个会话的对象而已。仍是以登陆人人网为例,使用requests
来实现。示例代码以下:
import requests url = "http://www.renren.com/PLogin.do" data = {"email":"970138074@qq.com",'password':"pythonspider"} 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" } # 登陆 session = requests.session() session.post(url,data=data,headers=headers) # 访问大鹏我的中心 resp = session.get('http://www.renren.com/880151247/profile') print(resp.text)
对于那些已经被信任的SSL整数的网站,好比https://www.baidu.com/
,那么使用requests
直接就能够正常的返回响应。示例代码以下:
resp = requests.get('http://www.12306.cn/mormhweb/',verify=False) print(resp.content.decode('utf-8'))