爬虫

爬虫的定义:

向网站发送请求,获取资源后分析并获取需要的数据

爬虫的基本流程:

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

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

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

保存数据:
保存到数据库,文件

请求与响应

#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

Response

#1、响应状态
    200:代表成功
    301:代表跳转
    404:文件不存在
    403:权限
    502:服务器错误

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

 请求库之requests库

一介绍

介绍:使用requests可以模拟浏览器的请求,比起之前用到的urllib,requests模块的api更加便捷(本质就是封装了urllib3)

#注意:requests库发送请求将网页内容下载下来以后,并不会执行js代码,这需要我们自己分析目标站点然后发起新的request请求

#安装:pip3 install requests

#各种请求方式:常用的就是requests.get()和requests.post()
>>> import requests
>>> r = requests.get('https://api.github.com/events')
>>> r = requests.post('http://httpbin.org/post', data = {'key':'value'})
>>> r = requests.put('http://httpbin.org/put', data = {'key':'value'})
>>> r = requests.delete('http://httpbin.org/delete')
>>> r = requests.head('http://httpbin.org/get')
>>> r = requests.options('http://httpbin.org/get')

基于GET请求

基本请求

import requests
response=requests.get('http://dig.chouti.com/')
print(response.text)
#在请求头内将自己伪装成浏览器,否则百度不会正常返回页面内容
import requests
response=requests.get('https://www.baidu.com/s?wd=python&pn=1',
                      headers={
                        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
                      })
print(response.text)



#如果查询关键词是中文或者有其他特殊符号,则不得不进行url编码
from urllib.parse import urlencode
wd='egon老师'
encode_res=urlencode({'k':wd},encoding='utf-8')
keyword=encode_res.split('=')[1]
print(keyword)
# 然后拼接成url
url='https://www.baidu.com/s?wd=%s&pn=1' %keyword

response=requests.get(url,
                      headers={
                        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
                      })
res1=response.text
自己拼接GET参数
#上述操作可以用requests模块的一个params参数搞定,本质还是调用urlencode
from urllib.parse import urlencode
wd='egon老师'
pn=1

response=requests.get('https://www.baidu.com/s',
                      params={
                          'wd':wd,
                          'pn':pn
                      },
                      headers={
                        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
                      })
res2=response.text

#验证结果,打开a.html与b.html页面内容一样
with open('a.html','w',encoding='utf-8') as f:
    f.write(res1) 
with open('b.html', 'w', encoding='utf-8') as f:
    f.write(res2)
params参数的使用

带参数的GET请求(headers)

#通常我们在发送请求时都需要带上请求头,请求头是将自身伪装成浏览器的关键,常见的有用的请求头如下
Host
Referer #大型网站通常都会根据该参数判断请求的来源
User-Agent #客户端
Cookie #Cookie信息虽然包含在请求头里,但requests模块有单独的参数来处理他,headers={}内就不要放它了
#添加headers(浏览器会识别请求头,不加可能会被拒绝访问,比如访问https://www.zhihu.com/explore)
import requests
response=requests.get('https://www.zhihu.com/explore')
response.status_code #500



#自己定制headers
headers={
    'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36',

}
respone=requests.get('https://www.zhihu.com/explore',
                     headers=headers)
print(respone.status_code) #200
View Code

带参数的GET请求(cookies)

#登录github,然后从浏览器中获取cookies,以后就可以直接拿着cookie登录了,无需输入用户名密码
#用户名:egonlin 邮箱378533872@qq.com 密码lhf@123

import requests

Cookies={   'user_session':'wGMHFJKgDcmRIVvcA14_Wrt_3xaUyJNsBnPbYzEL6L0bHcfc',
}

response=requests.get('https://github.com/settings/emails',
             cookies=Cookies) #github对请求头没有什么限制,我们无需定制user-agent,对于其他网站可能还需要定制

print('378533872@qq.com' in response.text) #True
View Code

基于POST请求

介绍

#GET请求
HTTP默认的请求方法就是GET
     * 没有请求体
     * 数据必须在1K之内!
     * GET请求数据会暴露在浏览器的地址栏中

GET请求常用的操作:
       1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
       2. 点击页面上的超链接也一定是GET请求
       3. 提交表单时,表单默认使用GET请求,但可以设置为POST

#POST请求
(1). 数据不会出现在地址栏中
(2). 数据的大小没有上限
(3). 有请求体
(4). 请求体中如果存在中文,会使用URL编码!

#!!!requests.post()用法与requests.get()完全一致,特殊的是requests.post()有一个data参数,用来存放请求体数据

发送post请求,模拟浏览器的登录行为

'''
一 目标站点分析
    浏览器输入https://github.com/login
    然后输入错误的账号密码,抓包
    发现登录行为是post提交到:https://github.com/session
    而且请求头包含cookie
    而且请求体包含:
        commit:Sign in
        utf8:✓
        authenticity_token:lbI8IJCwGslZS8qJPnof5e7ZkCoSoMn6jmDTsL1r/m06NLyIbw7vCrpwrFAPzHMep3Tmf/TSJVoXWrvDZaVwxQ==
        login:egonlin
        password:123



二 流程分析
    先GET:https://github.com/login拿到初始cookie与authenticity_token
    返回POST:https://github.com/session, 带上初始cookie,带上请求体(authenticity_token,用户名,密码等)
    最后拿到登录cookie

```
ps:如果密码时密文形式,则可以先输错账号,输对密码,然后到浏览器中拿到加密后的密码,github的密码是明文
```

'''

import requests
import re

#第一次请求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授权)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN

#第二次请求:带着初始cookie和TOKEN发送POST请求给登录页面,带上账号密码
data={
    'commit':'Sign in',
    'utf8':'',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )

login_cookie=r2.cookies.get_dict()

#第三次请求:以后的登录,拿着login_cookie就可以,比如访问一些个人配置
r3=requests.get('https://github.com/settings/emails',
                cookies=login_cookie)

print('317828332@qq.com' in r3.text) #True

自动登录github(自己处理cookie信息)
View Code
import requests
import re

session=requests.session()
#第一次请求
r1=session.get('https://github.com/login')
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN

#第二次请求
data={
    'commit':'Sign in',
    'utf8':'',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}
r2=session.post('https://github.com/session',
             data=data,
             )

#第三次请求
r3=session.get('https://github.com/settings/emails')

print('317828332@qq.com' in r3.text) #True
requests.session()自动帮我们保存cookie信息

补充

requests.post(url='xxxxxxxx',
              data={'xxx':'yyy'}) #没有指定请求头,#默认的请求头:application/x-www-form-urlencoed

#如果我们自定义请求头是application/json,并且用data传值, 则服务端取不到值
requests.post(url='',
              data={'':1,},
              headers={
                  'content-type':'application/json'
              })

requests.post(url='',
              json={'':1,},
              ) #默认的请求头:application/json
View Code
原文地址:https://www.cnblogs.com/xinfan1/p/11928940.html