爬虫的概念

什么是爬虫
爬虫是一个应用程序,目的是为了从互联网中获取免费,有价值的数据
互联网
是由不同的计算机通过某种介质相互连接组成,
互联网是为了使得不同计算机之间可以交换数据
上网指的是,连接到互联网中,获取需要的数据
爬虫的价值
我们可以把互联网比喻为一座矿山,爬虫就相当于旷工,各大网站就相当于矿石,为我们提供免费的资源
爬虫的原理:
模拟浏览器 -- 获取服务器返回的数据 -- 解析数据 -- 存储
HTTP协议:
HTTP是基于请求响应模型,我们在编写爬虫的时候,要关注的点就是请求

1.url

2.请求方法
get
post

3.状态码
200 请求成功
3XX 重定向
4XX 客户端发送的请求有错误
5XX 服务器端发生了错误

4.请求参数
get参数放在URL后
post参数放在请求体中body中

5.请求头
cookie: 用于识别用户的身份,通常在访问一些私有的页面时需要使用cookie
User-Agent:用户代理,用于标识是由什么客户端发起的请求
referer: 用于判断用户是从哪个链接跳过来的

6.请求体
仅当请求方法为post时才有请求体

7.响应头
location:当状态码为3XX的时候,这个参数是有用的

8.响应体
1.html 使用re 或是其他来解析
2.二进制 直接写入文件
3.json 反序列化即可

 

代码部分

# 1.爬取首页数据,解析获取视频的详情链接
# 2.遍历每一个详情链接,并访问
# 3.从详情页面解析得到需要的数据 (视频链接,标题,详情,时间,收藏次数)

import requests
import re
import os
from threading import Thread
from concurrent.futures import ThreadPoolExecutor


base_url = "https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId={id}&start={start}"

# 指定请求的页数
page = 2

# 请求的分类
categoryId = 1


def get_data(start):
url = base_url.format(id=categoryId,start=start)
res = requests.get(url)
return res.text


def parser_index(text):
base_url = "https://www.pearvideo.com/"
urls = re.findall('<a href="(.*?)" class="vervideo-lilink actplay">',text)
urls = [base_url + i for i in urls]
# print(urls)
return urls

def get_details(url):
res = requests.get(url)
print(res.status_code)
return res.text

def parser_details(text):
# 视频的地址
video_url = re.search(r'srcUrl="(.*?\.mp4)"',text).group(1)
# 标题
title = re.search('<h1 class="video-tt">(.*?)</h1>',text).group(1)
# 详情
content = re.search('<div class="summary">(.*?)</div>',text).group(1)
# 时间
date = re.search('<div class="date">(.*?)</div>', text).group(1)
# 点赞数量
count = re.search('<div class="fav" data-id=".*?">(.*?)</div>', text).group(1)

return {"video_url":video_url,"title":title,"content":content,"date":date,"count":count}


def download_video(url,title):
data = requests.get(url)

if not os.path.exists("videos"):
os.makedirs("videos")
filename = os.path.join("videos",title)+".mp4"
filename = filename.replace(":","_")

with open(filename,"wb") as f:
f.write(data.content)
print("%s download finished!" % title)


if __name__ == '__main__':
pool = ThreadPoolExecutor(5)
for i in range(page):
data =get_data(i*12)
urls = parser_index(data)
for i in urls:
res = get_details(i)
dic = parser_details(res)
print(dic)
pool.submit(download_video,dic["video_url"],dic["title"])




第二部分
# 1.爬取首页数据,解析获取视频的详情链接
# 2.遍历每一个详情链接,并访问
# 3.从详情页面解析得到需要的数据 (视频链接,标题,详情,时间,收藏次数)

import requests
import re
import os
from threading import Thread
from concurrent.futures import ThreadPoolExecutor


base_url = "https://www.pearvideo.com/"

def get_index():
res = requests.get(base_url,headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
"referer": "https: // www.baidu.com / link?url = fUq54ztdrrLaIUXa - p6B9tuWXC3byFJCyBKuvuJ_qsPw8QLrWIfekFKGgmhqITyF & wd = & eqid = c5366da10000199a000000025c45768a"
})
return res.text

def parser_index(text):
urls = re.findall('<a href="(.*?)" class="vervideo-lilink actplay">',text)
urls = [base_url + i for i in urls]
# print(urls)
return urls

def get_details(url):
res = requests.get(url)
print(res.status_code)
return res.text

def parser_details(text):
# 视频的地址
video_url = re.search(r'srcUrl="(.*?\.mp4)"',text).group(1)
# 标题
title = re.search('<h1 class="video-tt">(.*?)</h1>',text).group(1)
# 详情
content = re.search('<div class="summary">(.*?)</div>',text).group(1)
# 时间
date = re.search('<div class="date">(.*?)</div>', text).group(1)
# 点赞数量
count = re.search('<div class="fav" data-id=".*?">(.*?)</div>', text).group(1)

return {"video_url":video_url,"title":title,"content":content,"date":date,"count":count}


def download_video(url,title):
data = requests.get(url)

if not os.path.exists("videos"):
os.makedirs("videos")
filename = os.path.join("videos",title)+".mp4"
filename = filename.replace(":","_")

with open(filename,"wb") as f:
f.write(data.content)
print("%s download finished!" % title)


if __name__ == '__main__':
pool = ThreadPoolExecutor(5)
data = get_index()
urls = parser_index(data)
for i in urls:
t = get_details(i)
dic = parser_details(t)
# Thread(target=download_video,args=(dic["video_url"],dic["title"])).start()
pool.submit(download_video,dic["video_url"],dic["title"])
print("submit task",dic["title"])

print("submit finished")

# reqType=5 固定
# categoryId 分类id
# start 从第几个开始





reques模块使用方法
"""
两个主要的函数
get
post
"""
import requests
kwd = "吴秀波出轨门"
# URL编码
from urllib.parse import urlencode
res = urlencode({"wd":kwd})
print(res)

headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}

url = "https://www.baidu.com/s"
#直接将参数放在 params中 会自动进行url编码
# response = requests.get(url,headers=headers,params={"wd":kwd})
# print(response.status_code)
# print(response.text)

# 添加数据到请求头中
# response = requests.get(url,headers={
# # 把你的数据加在这里
# },params={"wd":kwd})
# print(response.status_code)
# print(response.text)


# post请求参数
# 其他参数与get一致,请求体放在data中
# requests.post(data={})

# 返回值的处理
# response = requests.get(url,headers=headers,params={"wd":kwd})
# print(response.status_code) # 状态码
# print(response.text) # 将结果以文本的形式返回
# response.content # 将结果以二进制的方式返回
# response.json() # 将数据直接反序列化得到字典或是列表


模拟登录github
"""
1.请求登陆页面 获取token cookie
2.发生登陆的post请求,将用户名密码 和token 放在请求体中,cookie放在请求头中

"""
import requests
import re
login_url = "https://github.com/login"

headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}

res1 = requests.get(login_url,headers=headers)

print(res1.status_code)
# 从响应体中获取token
token = re.search('name="authenticity_token" value="(.*?)"',res1.text).group(1)
print(token)
# 保存cookie
login_cookie = res1.cookies.get_dict()
print(login_cookie)

# 发送登陆请求
res2 = requests.post("https://github.com/session",
headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"},
cookies = login_cookie,
data={
"commit": "Sign in",
"utf8": "✓",
"authenticity_token": token,
"login": "yangyuanhu",
"password": "123654asd"},
# 是否允许自动重定向
allow_redirects = False)
print(res2.status_code)

# 用户登录成功后的cookie
user_cookie = res2.cookies.get_dict()

# 访问主页
res3 = requests.get("https://github.com/settings/profile",cookies = user_cookie,headers = headers)
print(res3.status_code)
print(res3.text)
# "https://github.com/settings/profile"


    # 爬虫简介

### 什么是爬虫

​	爬虫是一种应用程序,用于从互联网中获取有价值的数据,从本质上来看,属于client客户端程序。

### 互联网简介

​	互联网是由各种计算机设备,通过连接介质相互连接而组成的,其目的就是为了能在不同计算机之间传输数据,并且在互联网上有大量的数据是免费的。如果没有互联网,你只能拿着u盘过去拷贝。。

### 爬虫的原理

​	通常我们所谓的上网,其实本质就是用计算机通过网络去访问另一台计算机上的数据,而这些数据通常以网页的形式存在于服务器上,网页本质上就是一个文本文件,要想得到有价值的数据,第一步就是要得到这些网页数据,这就需要**分析浏览器与服务器之间到底是如何通讯的,然后模拟浏览器来与服务器通讯,从而获取数据。**当然爬虫不仅限于爬取网页,还可爬取移动设备常用的json数据等等,以及其他格式的二进制数据等等。

### 爬虫的价值

​	互联网中最宝贵的就是数据了,例如淘宝的商品数据,链家的房源信息,拉钩的招聘信息等等,这些数据就像一座矿山,爬虫就像是挖矿的工具,掌握了爬虫技术,你就成了矿山老板,各网站都在为你免费提供数据。

### 爬虫的爬取过程

​	分析--模拟请求--解析数据--存储

# HTTP请求分析

首先要明确的是:爬虫的核心原理就是模拟浏览器发送HTTP协议来获取服务器上的数据,那么要想服务器接受你的请求,则必须将自己的请求伪装的足够像,这就需要我们去分析浏览器是如何发送的HTTP请求

其次:HTTP协议是基于请求响应模型的,客户端发送请求到服务器,服务器接受请求,处理后返回响应数据,需要关注的重点在于请求数据,只有服务器认为合格合法的请求才会得到服务器的响应。

### 利用chrome开发者工具来分析请求

chrome浏览器提供强大的开发者工具我们可以利用它来查看浏览器与服务器的整个通讯过程

![image-20190114194039219](https://ws1.sinaimg.cn/large/006tNc79ly1fz6ckp34m4j313u0o9n3z.jpg)

上图划出了常用的几个操作,如清空请求,保留日志等等,另一个常用操作就是清空cookie信息

打开chrome的设置页面搜索cookie就可以找到清空按钮。

![image-20190120201342706](https://ws3.sinaimg.cn/large/006tNc79gy1fzdb8vix2cj30dw0df0tw.jpg)

## 请求流程分析

#### 请求地址

​	浏览器发送的请求URL地址

#### 请求方法

​	get  中文需要URL编码,参数跟在地址后面

​	post 参数放在body中

#### 请求头

![image-20190120195336647](https://ws4.sinaimg.cn/large/006tNc79gy1fzdanz4zvvj30l508swgv.jpg)

​	cookie,需要登录成功才能访问的页面就需要传递cookie,否则则不需要cookie

​	user-agent,用户代理,验证客户端的类型

​	referer,引用页面,判断是从哪个页面点击过来的

#### 请求体

![image-20190120200016406](https://ws3.sinaimg.cn/large/006tNc79gy1fzdauwhqu1j30ct04gq3i.jpg)

​	只在post请求时需要关注,通常post请求参数都放在请求体中,例如登录时的用户名和密码

#### 响应头

![image-20190120195155247](https://ws1.sinaimg.cn/large/006tNc79gy1fzdam9rejqj30jw05cdgx.jpg)

​	**location**:重定向的目标地址,仅 在状态码为3XX时出现,需要考虑重定向时的方法,参数等。。,浏览器会自动重定向,request模块也会。

​	**set-cookie**:服务器返回的cookie信息,在访问一些隐私页面是需要带上cookie

#### 响应体

​	服务器返回的数据,可能以下几种类型

​	**HTML格式的静态页面**		需要解析获取需要的数据

​	**json个格式的结构化数据**	直接就是纯粹的数据

​	 **二进制数据**				通过文件操作直接写入文件



# 爬取梨视频

​	

# request模块的使用

## get请求

#### 请求参数

1.参数拼接时中文需要URLEncode,可以使用urllib中的编码函数来完成

```python
from urllib.parse import urlencode
import requests

params = {"wd":"美女"}
# 必须以字典类型传入需要编码的数据 得到拼接收的参数字符串
res = urlencode(params,encoding="utf-8")

url = "https://www.baidu.com/s"
url = url+"?"+res # 拼接参数

response = requests.get(url)

with open("test.html","wb") as f:
    f.write(response.content)
```

2.也可以直接将请求参数传给get的函数的params参数,get方法会自动完成编码

```python
import requests
# 参数字典
params = {"wd":"美女"}

url = "https://www.baidu.com/s"
# 直接传给params参数
response = requests.get(url,params=params)

with open("test.html","wb") as f:
    f.write(response.content)
```

上述的代码无法请求完成的数据 因为百度服务器有限制,必须制定用户代理,user-agent为浏览器才行

#### 添加请求头

```python
import requests

params = {"wd":"美女"}
url = "https://www.baidu.com/s"
headers = {
"user-agent" : 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36'
}
response = requests.get(url,params=params,headers=headers)

with open("test.html","wb") as f:
```

#### cookies

可以在headers中直接添加键值对也可以单独使用get方法的cookies参数

```python
url = "https://github.com/yangyuanhu"
headers = {
    "User-Agent" : 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36',
    "Cookie":"_octo=GH1.1.1155792533.1532919557; _ga=GA1.2.1847433334.1534242542; has_recent_activity=1; user_session=Z5AQmC_Wv4wvM-_Nc3Bj0PQn6nITSonDcPkw4GZ1g0jFIqbe; __Host-user_session_same_site=Z5AQmC_Wv4wvM-_Nc3Bj0PQn6nITSonDcPkw4GZ1g0jFIqbe; logged_in=yes; dotcom_user=yangyuanhu; tz=Asia%2FShanghai; _gat=1; _gh_sess=eERwWHk1NVBjOEhIRmxzckcrcWlpVCtUM2hWL0prNlIyNXdTdC9ab0FSZWR5MEZlYW5OVGNoTEdJQUN0K0xkNXVmTEVpK2RRU1VZTUF6NkJHM1JMejNtaVhReXg2M3Vsb0JvcG8vNDNENjNBcXVvcFE4Tmp4SFhpQ3Z3S2ZZZEIwTGNkVW5BR01qVHlCNEFqTnZFcllhN3NwT1VJblZYWElLOGowN3ZaZVpZTFVHQlFtZkh3K1hnclBWalB1Mk1XLS1wNjFjMlBxUHljU2paK2RXU3M5eDB3PT0%3D--8cdf657174d2acac7cc0459da667accc8a2d0f5e",
    "Referer": "https://github.com/"
}
response = requests.get(url,headers=headers)
with open("test.html","wb") as f:
    f.write(response.content)

# 使用cookies参数  注意需要拆分为单独的键值对
#response = requests.get(url,headers=headers,cookies={"_octo":"GH1.1.1155792533.1532919557"})
```

## POST请求

模拟登录流程并爬取github私有页面




    













posted @ 2019-01-21 20:22  不沉之月  阅读(1287)  评论(0编辑  收藏  举报