20200224 爬虫-requests模块

## 1 爬虫介绍

## 2 requests模块

-爬取梨视频,豆瓣电影,妹子图

## 3 bs4模块

-爬取汽车之家新闻

## 4 selenium模块

-爬取京东商品信息

## 反扒代理池,cookie池,验证码的破解

-如何自己写代理池(如何用第三方,开源)

-云打码平台

## 5 Mongodb

## 6 scrapy框架(爬虫界的django)

-整站爬取cnblogs文章

## 7 分布式爬虫

-在上面的基础上,做成分布式

--app爬取(理论上分析)

--爬取会员视频(如何做)

--破解XX验证码(不要想这些事)

爬虫

爬虫介绍

爬取的都是http/https的数据,移动端的数据,发送请求获取数据,并不是只有python能做爬虫(任何语言都可以做爬虫),python比较便捷,模块多,上手快,爬虫框架scrapy

发送http请求(requests模块)-----》服务端返回数据(咱们要爬取的网站)-----》拿到数据解析(re,bs4)(json/html)------》入库保存 (文件,mysql,redis) ------》后续可以做分析

#1、什么是互联网?
    互联网是由网络设备(网线,路由器,交换机,防火墙等等)和一台台计算机连接而成,像一张网一样。

#2、互联网建立的目的?
    互联网的核心价值在于数据的共享/传递:数据是存放于一台台计算机上的,而将计算机互联到一起的目的就是为了能够方便彼此之间的数据共享/传递,否则你只能拿U盘去别人的计算机上拷贝数据了。

#3、什么是上网?爬虫要做的是什么?
    我们所谓的上网便是由用户端计算机发送请求给目标计算机,将目标计算机的数据下载到本地的过程。
    #3.1 只不过,用户获取网络数据的方式是:
      浏览器提交请求->下载网页代码->解析/渲染成页面。

​```
#3.2 而爬虫程序要做的就是:
  模拟浏览器发送请求->下载网页代码->只提取有用的数据->存放于数据库或文件中
 
#3.1与3.2的区别在于:
​```

      我们的爬虫程序只提取网页代码中对我们有用的数据

#4、总结爬虫
    #4.1 爬虫的比喻:
      如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的猎物/数据

​```
#4.2 爬虫的定义:
​```

      向网站发起请求,获取资源后分析并提取有用数据的程序 

​```
#4.3 爬虫的价值:
  互联网中最有价值的便是数据,比如天猫商城的商品信息,链家网的租房信息,雪球网的证券投资信息等等,这些数据都代表了各个行业的真金白银,可以说,谁掌握了行业内的第一手数据,谁就成了整个行业的主宰,如果把整个互联网的数据比喻为一座宝藏,那我们的爬虫课程就是来教大家如何来高效地挖掘这些宝藏,掌握了爬虫技能,你就成了所有互联网信息公司幕后的老板,换言之,它们都在免费为你提供有价值的数据。
​```

流程

#1、发起请求
使用http库向目标站点发起请求,即发送一个Request
Request包含:请求头、请求体等

#2、获取响应内容
如果服务器能正常响应,则会得到一个Response
Response包含:html,json,图片,视频等

#3、解析内容
解析html数据:正则表达式,第三方解析库如Beautifulsoup,pyquery等
解析json数据:json模块
解析二进制数据:以b的方式写入文件

#4、保存数据
数据库
文件

请求与响应

#http协议:http://www.cnblogs.com/linhaifeng/articles/8243379.html

#Request:用户将自己的信息通过浏览器(socket client)发送给服务器(socket server)

#Response:服务器接收请求,分析用户发来的请求信息,然后返回数据(返回的数据中可能包含其他链接,如:图片,js,css等)

#ps:浏览器在接收Response后,会解析其内容来显示给用户,而爬虫程序在模拟浏览器发送请求然后接收Response后,是要提取其中的有用数据。

request

#1、请求方式:
    常用的请求方式:GET,POST
    其他请求方式:HEAD,PUT,DELETE,OPTHONS

​```
ps:用浏览器演示get与post的区别,(用登录演示post)

post与get请求最终都会拼接成这种形式:k1=xxx&k2=yyy&k3=zzz
post请求的参数放在请求体内:
    可用浏览器查看,存放于form data内
get请求的参数直接放在url后
​```

#2、请求url
    url全称统一资源定位符,如一个网页文档,一张图片
    一个视频等都可以用url唯一来确定

​```
url编码
https://www.baidu.com/s?wd=图片
图片会被编码(看示例代码)
​```

​```
网页的加载过程是:
加载一个网页,通常都是先加载document文档,
在解析document文档的时候,遇到链接,则针对超链接发起下载图片的请求
​```

#3、请求头
    User-agent:请求头中如果没有user-agent客户端配置,
    服务端可能将你当做一个非法用户
    host
    cookies:cookie用来保存登录信息

​```
一般做爬虫都会加上请求头
​```

#4、请求体
    如果是get方式,请求体没有内容
    如果是post方式,请求体是format data


ps:
1、登录窗口,文件上传等,信息都会被附加到请求体内
2、登录,输入错误的用户名密码,然后提交,就可以看到post,正确登录后页面通常会跳转,无法捕捉到post 

response

#1、响应状态
    200:代表成功
    301:代表跳转	#  301是永久重定向,而302是临时重定向
    404:文件不存在
    403:权限
    502:服务器错误

#2、Respone header
    set-cookie:可能有多个,是来告诉浏览器,把cookie保存下来
    
#3、preview就是网页源代码
    最主要的部分,包含了请求资源的内容
    如网页html,图片
    二进制数据等

robots文件,规定爬取的内容

requests模块

Request支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。

在python内置模块的基础上进行了高度的封装,从而使得python进行网络请求时,变得人性化,使用Requests可以轻而易举的完成浏览器可有的任何操作。

导入

pip3 install requests
import requests

请求模式

requests.get(‘https://github.com/timeline.json’)                                # GET请求
requests.post(“http://httpbin.org/post”)                                        # POST请求
requests.put(“http://httpbin.org/put”)                                          # PUT请求
requests.delete(“http://httpbin.org/delete”)                                    # DELETE请求
requests.head(“http://httpbin.org/get”)                                         # HEAD请求
requests.options(“http://httpbin.org/get” )                                     # OPTIONS请求

get请求

import requests

r = requests.get('https://github.com/Ranxf')       # 最基本的不带参数的get请求

r1 = requests.get(url='http://dict.baidu.com/s', params={'wd': 'python'})      # 带参数的get请求

传递参数

#第一种方式

ret=requests.get('http://127.0.0.1:8001/?name=刘清政&age=18',)




#第二种方式(推荐使用)

ret=requests.get('http://127.0.0.1:8001/',params={'name':'刘清政','age':19})




#有什么区别
#第二种方式,如果有中文,会自动转码
# https://www.baidu.com/s?wd=%E7%BE%8E%E5%A5%B3
#补充,可以通过urlencode进行转码

from urllib.parse import urlencode

print(urlencode({'name':'刘清政'},encoding='utf-8'))

print(ret.text)

携带cookie的两种方式

#第一种方式
ret=requests.get('http://www.baidu.com',
                 headers={
                     'cookie':'key:value;key2:value2'
                 })



#第二种方式(推荐)
ret=requests.get('http://www.baidu.com',
            cookies={"key":'value','key2':'value21'}
                 )
                 
不过一般使用session进行设置cookies

post请求

发送post请求,携带数据,两个位置,一个是请求地址中,一个是请求体中

# params: 放到请求连接地址中的参数
# data:请求体中的参数

ret=requests.post('http://127.0.0.1:8001/',params={'name':'lqz','age':18},data={'name':'egon','age':17})

print(ret)

实例

# 1、基本POST实例
  
import requests
  
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)
  
print(ret.text)
  
  
# 2、发送请求头和数据实例
  
import requests
import json
  
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
  
ret = requests.post(url, data=json.dumps(payload), headers=headers)
  
print(ret.text)
print(ret.cookies)

post发送json请求

import requests
import json
 
r = requests.post('https://api.github.com/some/endpoint', data=json.dumps({'some': 'data'}))
print(r.json())

定制请求头headers

header = {'user-agent': 'my-app/0.0.1''}
cookie = {'key':'value'}
 r = requests.get/post('your url',headers=header,cookies=cookie) 
          

data = {'some': 'data'}
headers = {'content-type': 'application/json',
           'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'}
 
r = requests.post('https://api.github.com/some/endpoint', data=data, headers=headers)
print(r.text)

常见headers

"User-Agent": 
	向访问网站提供你所使用的浏览器类型及版本、操作系统及版本、浏览器内核、等信息的标识
	
"Referer": 
	当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理
	
Authorization:
	授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中;

Cookie:
	这是最重要的请求头信息之一;一般可以直接复制,对于一些变化的可以选择构造(python中的一些库也可以实现),详情请了解http.cookiejar,python 3.x 爬虫基础---Urllib详解有提及。

From:
	请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它;

If-Modified-Since:
	只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答;

Pragma:
	指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝;

UA-Pixels,UA-Color,UA-OS,UA-CPU:
	由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型。

Origin:
	Origin字段里只包含是谁发起的请求,并没有其他信息。跟Referer不一样的 是Origin字段并没有包含涉及到用户隐私的URL路径和请求内容,这个尤其重要。

并且Origin字段只存在于POST请求,而Referer则存在于所有类型的请求;

常见user_agent

user_agent_list = [
 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
  'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3',
 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)',
 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
 'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)',
 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0',
 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
]

Django后端

Django中的request对象有META字典,请求头所有的东西,都在这个字典中

监听 127.0.0.1:8080和0.0.0.0:8080的区别,前者只允许本机访问,后者允许任意机器访问
ALLOWED_HOSTS = ['*'] 程序层面,允许任意ip地址访问



请求头的数据从request.META中取,只不过前面加了个HTTP,把请求的key变为了大写


# 问题
post请求在请求地址中可以不以带请求参数?如果带了,从哪拿?
	连接地址中:从GET
	如果在请求体中的参数:从POST中

三种编码格式

urlencoded,json,form-data

django request.POST中之所有能取出来数据来,因为django框架从请求体中取出数据,放到POST中去了,编码格式必须是urlencoded

如果编码格式是json格式,django不干这个事,request.POST中取不出来,request.body取出来中自行处理

http请求体:

urlencoded:name=lqz&age=19

json:{"name":"刘清政","":""}

form-data:很复杂

代理proxies

#   ssl(了解)
#   代理(重点) 代理池 (正向代理)
# 正向代理和反向代理?(自己查?作业)
# 使用代理,防止服务端封咱们的ip(免费的:不稳定    收费的:稳定)
# 代理匿名度:高匿  透明

# requests发送请求如何使用代理

ret=requests.get('http://101.133.225.166:8088/',
                 proxies={'http':'222.95.241.88:3000'}
 )
print(ret.text)
# django如何取出客户端的ip地址(request.META.get('REMOTE_ATTR'),  取出的是代理ip
# 真正的项目中,一般会使用代理池,你自己是可以搭建代理池的。你去爬取免费代理,

# https://github.com/jhao104/proxy_pool  网上开源的代理池
# django 如何取到哪个ip地址使用了代理?

超时设置timeout

ret=requests.get('http://www.baidu.com',timeout=0.01)
1 requests模块就是模拟http请求,请求有什么,requests模块就可以放什么,headers(user-agent,referer),cookies,data/json,
2 如果不做爬虫,requests模块可以单独使用,以后涉及到两个服务(两个项目)之间做数据交互

上传文件

file={'myfile':open('baidu.html')}

ret=requests.post('http://127.0.0.1:8001/',files=file)
print(ret.text)

响应对象response

# 响应对象response
ret=requests.post('http://127.0.0.1:8001/',params={'name':'lqz','age':18},data={'name':'egon','age':17})

print(ret.text)
print(ret.content)  # 响应体的二进制格式,一旦请求的是图片。。。,
# print(ret.status_code) #响应的状态码

print(ret.cookies)   #对象,requests模块自己封装的对象
print(ret.cookies.get_dict()) #这个是字典
print(ret.url)
#列表,放的是重定向之前的response对象
print(ret.history[0].url)
ret.encoding 服务端的编码方式
###重点补充
session=requests.sessions()

# 再发送各种请求,不需要手动加cookie了,它自动处理了

解析json

ret=requests.post('http://127.0.0.1:8001/')
print(type(ret.text))  #str类型
print(type(ret.json())) #字典类型
# python 3.5 和python3.6以后  json 稍微改动了一下,3.5以前只能传  (json.loads(字符串))  3.6以后json.loads(字符串/bytes格式)
import json
json.loads()
# 你在项目开发中遇到的问题和如何解决的?
r.encoding                       #获取当前的编码
r.encoding = 'utf-8'             #设置编码
r.text                           #以encoding解析返回内容。字符串方式的响应体,会自动根据响应头部的字符编码进行解码。
r.content                        #以字节形式(二进制)返回。字节方式的响应体,会自动为你解码 gzip 和 deflate 压缩。

r.headers                        #以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None

r.status_code                     #响应状态码
r.raw                             #返回原始响应体,也就是 urllib 的 response 对象,使用 r.raw.read()   
r.ok                              # 查看r.ok的布尔值便可以知道是否登陆成功
 #*特殊方法*#
r.json()                         #Requests中内置的JSON解码器,以json形式返回,前提返回的内容确保是json格式的,不然解析出错会抛异常
r.raise_for_status()             #失败请求(非200响应)抛出异常

总结

# HTTP请求类型
# get类型
r = requests.get('https://github.com/timeline.json')
# post类型
r = requests.post("http://m.ctrip.com/post")
# put类型
r = requests.put("http://m.ctrip.com/put")
# delete类型
r = requests.delete("http://m.ctrip.com/delete")
# head类型
r = requests.head("http://m.ctrip.com/head")
# options类型
r = requests.options("http://m.ctrip.com/get")

# 获取响应内容
print(r.content) #以字节的方式去显示,中文显示为字符
print(r.text) #以文本的方式去显示

#URL传递参数
payload = {'keyword': '香港', 'salecityid': '2'}
r = requests.get("http://m.ctrip.com/webapp/tourvisa/visa_list", params=payload) 
print(r.url) #示例为http://m.ctrip.com/webapp/tourvisa/visa_list?salecityid=2&keyword=香港

#获取/修改网页编码
r = requests.get('https://github.com/timeline.json')
print (r.encoding)


#json处理
r = requests.get('https://github.com/timeline.json')
print(r.json()) # 需要先import json    

# 定制请求头
url = 'http://m.ctrip.com'
headers = {'User-Agent' : 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'}
r = requests.post(url, headers=headers)
print (r.request.headers)

#复杂post请求
url = 'http://m.ctrip.com'
payload = {'some': 'data'}
r = requests.post(url, data=json.dumps(payload)) #如果传递的payload是string而不是dict,需要先调用dumps方法格式化一下

# post多部分编码文件
url = 'http://m.ctrip.com'
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)

# 响应状态码
r = requests.get('http://m.ctrip.com')
print(r.status_code)
    
# 响应头
r = requests.get('http://m.ctrip.com')
print (r.headers)
print (r.headers['Content-Type'])
print (r.headers.get('content-type')) #访问响应头部分内容的两种方式
    
# Cookies
url = 'http://example.com/some/cookie/setting/url'
r = requests.get(url)
r.cookies['example_cookie_name']    #读取cookies
    
url = 'http://m.ctrip.com/cookies'
cookies = dict(cookies_are='working')
r = requests.get(url, cookies=cookies) #发送cookies

#设置超时时间
r = requests.get('http://m.ctrip.com', timeout=0.001)

#设置访问代理
proxies = {
           "http": "http://10.10.1.10:3128",
           "https": "http://10.10.1.100:4444",
          }
r = requests.get('http://m.ctrip.com', proxies=proxies)


#如果代理需要用户名和密码,则需要这样:
proxies = {
    "http": "http://user:pass@10.10.1.10:3128/",
}

爬取梨视频

# coding=utf-8
#!/usr/bin/env python3

' 爬取梨视频旅行类节目视频 '

__author__ = 'Fwzzz'



import requests
import re
import os


# 获取ajax中的url连接,一页显示12个视频
# https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=130&start=48&mrd=0.19150474798121242&filterIds=1654833,1654758,1654600,1646155,1645968,1645844,1645905,1645629,1645343,1645111,1645092,1644833,1644678,1644569,1644534
url = 'https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=130&start=0'
# 设置headers头部
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36','Referer': 'https://www.pearvideo.com/category_130'}
# 获取请求数据
response = requests.get(url,headers=header)
# print(response.text)

# 利用re清洗数据,获取每个网页中的视频连接列表
# <a href="video_1653882" class="vervideo-lilink actplay">
movie_url = re.findall('<a href="(.*?)" class="vervideo-lilink actplay">',response.text)
# print(movie_url)
# 对视频连接进行拼接,获取视频详情页
# https://www.pearvideo.com/video_1644569
for url in movie_url:
    m_url = f'https://www.pearvideo.com/{url}'
    # print(m_url
    # 视频详情页中获取真实的视频地址(在js中)
    res = requests.get(m_url,headers=header)
    # print(res.text)
    # srcUrl = "https://video.pearvideo.com/mp4/third/20200223/cont-1654833-11487675-115207-hd.mp4", vdoUrl = srcUrl
    m_url = re.findall('srcUrl="(.*?)",vdoUrl',res.text,re.S)[0]
    # 发送请求,获取视频的二进制数据
    movie = requests.get(m_url,headers = header)
    # print(movie.text)
    # 保存数据到本地
    print(f'-----正在下载{url}.MP4')
    with open(f'{url}.mp4','wb') as f:
        f.write(movie.content)
        print(f'{url}.MP4下载完毕-----')
原文地址:https://www.cnblogs.com/fwzzz/p/12460447.html