爬虫基本原理

一、爬虫是什么

1、什么是互联网?互联网建立的目的?

  互联网由网络设备和一台台计算机连接而成,像一张网一样。

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

2、什么是上网?爬虫需要做什么?

  所谓上网便是用户端计算机发送请求给目标计算机,将目标计算机的数据下载到本地的过程。

(1)通过浏览器上网时,用户获取网络数据的方式是:

  浏览器提交请求——>下载网页代码——>解析/渲染成页面。

(2)爬虫获取网络数据的过程:

  模拟浏览器发送请求——>下载网页代码——>只提取有用的数据——>存放于数据库或文件中。

(3)这两种获取方式区别:

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

3、爬虫概念总结

(1)爬虫比喻

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

(2)爬虫定义

  爬虫通过代码伪造浏览器发起请求,获取资源后分析并提取有用数据的程序。

(3)爬虫价值

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

二、爬虫的基本流程

  

1、发起请求

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

2、获取响应内容

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

3、解析内容

  解析html数据:正则表达式,第三方解析库如Beatifulsoup,pyquery等。

  解析json数据:json模块。

  解析二进制数据:以b的方式写入文件。

4、保存数据

  数据库、文件

三、请求和响应

1、Request(请求)

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

(1)请求方式

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

  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

  注意: 1)登录窗口,文件上传等,信息都会被附加到请求体内

        2)登录,输入错误的用户名密码,然后提交,就可以看到post;正确登录后页面通常会跳转,无法捕捉到post。

2、Response(响应)

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

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

(1)响应状态

    200:代表成功
    301:代表跳转
    404:文件不存在
    403:权限
    502:服务器错误

(2)Response header

  set-cookie:可能有多个,是来告诉浏览器,把cookie保存下来。

(3)preview就是网页源代码

  最主要的部分,包含了请求资源的内容,如网页html,图片二进制数据等。

四、项目示例

1、示例一:爬取汽车之家新闻资讯

"""
爬取汽车之家新闻页面数据
"""
import requests   # pip3 install requests
from bs4 import BeautifulSoup
import os


# 1.伪造浏览器发送请求
r1 = requests.get(
    url="http://www.autohome.com.cn/news/"
)

r1.encoding = "gbk"   # 字节按照gbk编码返回
# print(r1.text)   # 响应体
# print(r1.headers)   # 响应头


# 2.去响应体中解析出想要的数据
soup = BeautifulSoup(r1.text, "html.parser")

# 3.找名字按照规则:div标签且id=auto-channel-layload-article
container = soup.find(name="div", attrs={'id': "auto-channel-lazyload-article"})

# 4.去container中找所有li标签
li_list = container.find_all(name="li")
for tag in li_list:
    # print(tag)   # li标签内的所有内容

    """ 文章标题 """
    title = tag.find(name="h3")
    if not title:
        # h3为空的时候
        continue

    # 这里拿到的title是标签对象
    # print(title, type(title))   # <h3>16家银行/万亿授信 一汽将发力新能源</h3> <class 'bs4.element.Tag'>

    # title.text拿到标签文本
    print(title.text)       # 文章标题内容:桩跟车走 沃尔沃收购移动充电公司股份

    """ 文章简介 """
    summary = tag.find(name="p")
    print(summary.text)     # 文章简介:[汽车之家 新闻]  据中国一汽官方消息,日前中...各银行给中国一汽意向性授...

    """ 文章地址 """
    a = tag.find(name="a")
    # summary.attrs:打印出所有的标签属性
    # print(a.attrs)            # {'href': '//www.autohome.com.cn/news/201810/924097.html#pvareaid=102624'}
    # 可以发现a.attrs得到的是一个字典,因此可以用get方法回去字典值
    # print(a.attrs.get('href'))  # //www.autohome.com.cn/news/201810/924096.html#pvareaid=102624
    url = "https:" + a.attrs.get('href')
    print(url)              # https://www.autohome.com.cn/news/201810/924097.html#pvareaid=102624

    """ 文章配图地址 """
    img = tag.find(name="img")
    img_url = "https:" + img.get("src")  # 内部直接调用attrs.get
    print(img_url)         # 图片地址输出:https://www3.autoimg.cn/newsdfs/8K1Z4867.jpg

    """ 下载图片到本地imgs """
    r2 = requests.get(
        url=img_url
    )
    file_name = img_url.rsplit('/', maxsplit=1)[1]
    file_path = os.path.join('imgs', file_name)

    with open(file_path, "wb") as f:
        f.write(r2.content)

2、示例二:抓取抽屉新热榜新闻(携带user-agent)

"""
爬取抽屉新热榜新闻数据
"""

import requests
from bs4 import BeautifulSoup
import os


# 1.伪造浏览器发送请求
r1 = requests.get(
    url="https://dig.chouti.com/",

    # 伪装请求头
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
    }
)

# print(r1.text)

# 2.去响应体中解析出想要的数据
soup = BeautifulSoup(r1.text, "html.parser")

# 3.找名字按照规则:div标签且id=content-list
container = soup.find(name="div", attrs={"id": "content-list"})

# 4.去container中找到所有新闻内容
li_list = container.find_all(name="div", attrs={"class": "item"})

for tag in li_list:
    # print(tag)   # 每条新闻的所有内容

    """ 文章标题 """
    title = tag.find(name="a", attrs={"class": "show-content"})
    print("标题:", title.text.strip())   # strip():去除前后多余的空格

    """ 文章简介 """
    summary = tag.find(name="span", attrs={"class": "summary"})
    if not summary:
        continue
    print("摘要:", summary.text)

    """ 文章地址 """
    a = tag.find(name="a", attrs={"class": "show-content"})
    url = a.attrs.get('href')
    print("地址:", url)

    """ 文章配图地址 """
    img = tag.find(name="img")
    img_url = "https:" + img.get("original")    # 内部直接调用attrs.get
    print("图片地址:", img_url)

    """ 下载图片带本地/imgs_2 """
    r2 = requests.get(
        url=img_url
    )
    file_name = img_url.rsplit('/', maxsplit=1)[1]  # 取图片名
    file_name = file_name.rsplit('?', maxsplit=1)[0]
    file_path = os.path.join('imgs_2', file_name)

    with open(file_path, "wb") as f:
        f.write(r2.content)

3、示例三:对抽屉中新闻点赞

  第一次访问保留cookie,登录时需要再次携带。

"""
通过代码进行自动登录,然后对新闻点赞
"""
import requests

# ####################### 第一部分:登录 ######################

# 伪造浏览器发送get请求
r1 = requests.get(
    url="https://dig.chouti.com/",
    # 伪装请求头
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
    }
)

# print(r1.text)   # 响应体
# print(r1.headers)   # 响应头
# 查看cookie
r1_cookie_dict = r1.cookies.get_dict()
print(r1_cookie_dict)   # {'gpsd': 'a3b15f31b3f3c9815cf4a8202c1ba0a4', 'JSESSIONID': 'aaaMJJh_RM5aC-2uGWzAw'}


# 伪造浏览器发送post请求
r2 = requests.post(
    url="https://dig.chouti.com/login",   # 在浏览器尝试登录,控制台查看Network下login请求信息
    # 伪装请求头
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
    },
    # 伪造要发送的请求体数据
    data={
        "phone": "8618687883720",   # 账户
        "password": "w*****p",         # 密码
        "oneMonth":1
    },
    # 抽屉的防御爬虫策略:不看页面直接发POST的得到的cookie是错误的。第一次页面访问得到的cookie才是真的cookie
    cookies=r1_cookie_dict
)

# 查看返回结果
print(r2.text)
"""
错误:{"result":{"code":"21101", "message":"手机号或密码错误", "data":{}}}
正确:{"result":{"code":"9999", "message":"", "data":{"complateReg":"0","destJid":"cdu_54078126953"}}}
"""

# ####################### 第二部分:点赞 ######################
r3 = requests.post(
    url="https://dig.chouti.com/link/vote?linksId=22886331",
    # 伪装请求头
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
    },
    cookies=r1_cookie_dict
)

# 查看返回结果
print(r3.text)
"""
{"result":{"code":"30010", "message":"你已经推荐过了", "data":""}}
"""

  注意:抽屉的防御爬虫策略:不看页面直接发POST的得到的cookie是错误的。页面访问得到的cookie才是真的cookie。

4、示例四:自动登录github

(1)浏览器登录github分析

  故意输入错误的账户密码登录github:

  

  查看提交的post请求数据:

  

  服务响应页面是https://github.com/session,查看源码中form表单中token信息

  

(2)代码如下 

import requests
from bs4 import BeautifulSoup


# ########### 伪造浏览器发送get请求 #############
r1 = requests.get(
    url="https://github.com/login"
)
s1 = BeautifulSoup(r1.text, 'html.parser')

# 拿到token信息
token = s1.find(name="input", attrs={"name": "authenticity_token"}).get("value")
print(token)    # Y/OZ1lHKUHW0+...vMWEvRCzUrtkw==

# 拿到cookie
r1_cookie_dict = r1.cookies.get_dict()


# ########### 伪造浏览器发送post请求 ##############
r2 = requests.post(
    url="https://github.com/session",
    data={
        "commit": "Sign in",
        "utf8": "✓",
        "authenticity_token": token,
        "login": "hxxxxxx6",
        "password": "xxxxxxxx"
    },
    cookies=r1_cookie_dict
)

r2_cookie_dict = r2.cookies.get_dict()


# #########伪造浏览器发送get请求,尝试访问登录用户才能访问的页面######
r3 = requests.get(
    url="https://github.com/settings/emails",
    # cookies=r1_cookie_dict
    cookies=r2_cookie_dict     # 经测试验证,使用这个cookie可以拿到数据
)
print(r3.text)  # 在返回的html找到个人的邮箱信息,说明登录并访问成功

5、套路总结

  • 汽车之家
  • 抽屉新闻:携带user-agent。
  • 登录抽屉:第一次访问保留cookie,登录时需要再次携带。 
  • 自动登录github:获取csrf_token 及 到底携带哪一个cookie。

五、爬取拉勾网

1、登录查看“我的邀请页面”

  

  代码示例如下所示:

import re
import json
import requests

all_cookie_dict = {}
# ############################ 第一步访问登录页面 #################
r1 = requests.get(
    url="https://passport.lagou.com/login/login.html",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
    }
)
# print(r1.text)

"""查看登录页面源码
    <!-- 页面样式 -->    
    <!-- 动态token,防御伪造请求,重复提交 -->
<script>
    window.X_Anti_Forge_Token = '011025d5-fb0e-46be-a2a9-6ad036224062';
    window.X_Anti_Forge_Code = '62107713';
</script>
"""
token = re.findall("X_Anti_Forge_Token = '(.*)';", r1.text)[0]
print(token)   # '51a18f67-865e-4b8d-9e3f-aad9944611ee'

code = re.findall("X_Anti_Forge_Code = '(.*)';", r1.text)[0]
print(code)    # '28683037'

r1_cookie_dict = r1.cookies.get_dict()
all_cookie_dict.update(r1_cookie_dict)


# ######################## 第二步 去登录 #####################
r2 = requests.post(
    url="https://passport.lagou.com/login/login.json",
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",

        # 常规请求头
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "Host": "passport.lagou.com",
        "Origin": "https://passport.lagou.com",
        "Referer": "https://passport.lagou.com/login/login.html",

        # X-Requested-With:说明是ajax请求
        "X-Requested-With": "XMLHttpRequest",

        # 自定义请求头:动态token,防御伪造请求,重复提交
        "X-Anit-Forge-Code": code,
        "X-Anit-Forge-Token": token,
    },
    # 在登录失败的login.json中查看要发送的请求体数据
    data={
        "isValidate": "true",
        "username": "1xxxxxxx0",
        "password": "c94be20xxxxxxxxa89fea5a0f",   # 加密的密码写密文
        "request_form_verifyCode": "",
        "submit": ""
    },
    cookies=all_cookie_dict
)

r2_response_json = r2.json()   # 将字符串反序列化,把字符串变为字典

print(r2_response_json)  # {'content': {'rows': []}, 'message': '操作成功', 'submitToken': 'e1fa3919-679d-4aa0-8b9c-224b7d707ed2'}
print(r2)    # <Response [200]>

r2_cookie_dict = r2.cookies.get_dict()
all_cookie_dict.update(r2_cookie_dict)


# ######################## 第三步 grant.html #####################
r3 = requests.get(
    url="https://passport.lagou.com/grantServiceTicket/grant.html",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "passport.lagou.com",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r3_cookie_dict = r3.cookies.get_dict()
all_cookie_dict.update(r3_cookie_dict)

# 下一步要跳转的地址
print(r3.headers["Location"])  # 在响应头里包含:Location: https://www.lagou.com/?action=grantST&ticket=ST-30a4f4ce3dd


# ######################## 第四步 action=grantST&ticket=ST-30a4f4ce3d #####################
r4 = requests.get(
    url=r3.headers["Location"],
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "www.lagou.com",
        "Upgrade-Insecure-Requests": "1",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r4_cookie_dict = r4.cookies.get_dict()
print(r4_cookie_dict)
all_cookie_dict.update(r4_cookie_dict)


# ######################## 第五步 获取认证信息 #####################
r5 = requests.get(
    url=r4.headers["Location"],
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "www.lagou.com",
        "Upgrade-Insecure-Requests": "1",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r5_cookie_dict = r5.cookies.get_dict()
all_cookie_dict.update(r5_cookie_dict)
print(r5_cookie_dict)
print(r5.headers["Location"])


# ######################## 第六步 访问查看"我的邀请" #####################
# 在控制台network中查看invitation.html信息

r = requests.get(
    url="https://www.lagou.com/mycenter/invitation.html",
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Host": "www.lagou.com",
        "Upgrade-Insecure-Requests": "1",
        "Pragma": "no-cache",
    },
    cookies=all_cookie_dict
)

# print(r.text)   # 在网页中查看自己的用户名:<span class="unick bl">xxx</span>
print("萨xxx" in r.text)   # True

2、登录拉钩网修改个人信息

  拉勾网个人信息,原用户名是has222、职位是云平台工程师。

  代码示例如下所示:

import re
import json
import requests


all_cookie_dict = {}
# ############################ 第一步访问登录页面 #################
r1 = requests.get(
    url="https://passport.lagou.com/login/login.html",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
    }
)
# print(r1.text)

"""查看登录页面源码
    <!-- 页面样式 -->    
    <!-- 动态token,防御伪造请求,重复提交 -->
<script>
    window.X_Anti_Forge_Token = '011025d5-fb0e-46be-a2a9-6ad036224062';
    window.X_Anti_Forge_Code = '62107713';
</script>
"""
token = re.findall("X_Anti_Forge_Token = '(.*)';", r1.text)[0]
# print(token)   # '51a18f67-865e-4b8d-9e3f-aad9944611ee'

code = re.findall("X_Anti_Forge_Code = '(.*)';", r1.text)[0]
# print(code)    # '28683037'

r1_cookie_dict = r1.cookies.get_dict()
all_cookie_dict.update(r1_cookie_dict)


# ######################## 第二步 去登录 #####################
r2 = requests.post(
    url="https://passport.lagou.com/login/login.json",
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",

        # 常规请求头
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "Host": "passport.lagou.com",
        "Origin": "https://passport.lagou.com",
        "Referer": "https://passport.lagou.com/login/login.html",

        # X-Requested-With:说明是ajax请求
        "X-Requested-With": "XMLHttpRequest",

        # 自定义请求头:动态token,防御伪造请求,重复提交
        "X-Anit-Forge-Code": code,
        "X-Anit-Forge-Token": token,
    },
    # 在登录失败的login.json中查看要发送的请求体数据
    data={
        "isValidate": "true",
        "username": "1xxxxxxxx0",
        "password": "c94be204f3xxxxxxx89fea5a0f",   # 加密的密码写密文
        "request_form_verifyCode": "",
        "submit": ""
    },
    cookies=all_cookie_dict
)

r2_response_json = r2.json()   # 将字符串反序列化,把字符串变为字典

# print(r2_response_json)  # {'content': {'rows': []}, 'message': '操作成功', 'submitToken': 'e1fa3919-679d-4aa0-8b9c-224b7d707ed2'}
# print(r2)    # <Response [200]>

r2_cookie_dict = r2.cookies.get_dict()
all_cookie_dict.update(r2_cookie_dict)


# ######################## 第三步 grant.html #####################
r3 = requests.get(
    url="https://passport.lagou.com/grantServiceTicket/grant.html",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "passport.lagou.com",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r3_cookie_dict = r3.cookies.get_dict()
all_cookie_dict.update(r3_cookie_dict)

# 下一步要跳转的地址
# print(r3.headers["Location"])  # 在响应头里包含:Location: https://www.lagou.com/?action=grantST&ticket=ST-30a4f4ce3dd


# ######################## 第四步 action=grantST&ticket=ST-30a4f4ce3d #####################
r4 = requests.get(
    url=r3.headers["Location"],
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "www.lagou.com",
        "Upgrade-Insecure-Requests": "1",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r4_cookie_dict = r4.cookies.get_dict()
# print(r4_cookie_dict)
all_cookie_dict.update(r4_cookie_dict)


# ######################## 第五步 获取认证信息 #####################
r5 = requests.get(
    url=r4.headers["Location"],
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "www.lagou.com",
        "Upgrade-Insecure-Requests": "1",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r5_cookie_dict = r5.cookies.get_dict()
all_cookie_dict.update(r5_cookie_dict)
# print(r5_cookie_dict)
# print(r5.headers["Location"])


# ######################## 第六步 模拟重定向 #####################
r6 = requests.get(
    url=r5.headers["Location"],
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "www.lagou.com",
        "Upgrade-Insecure-Requests": "1",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r6_cookie_dict = r6.cookies.get_dict()
all_cookie_dict.update(r6_cookie_dict)
print(r6.headers['Location'])   # https://www.lagou.com/


# ######################## 第七步 模拟重定向 #####################
r7 = requests.get(
    url=r6.headers["Location"],
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://passport.lagou.com/login/login.html",
        "Host": "www.lagou.com",
        "Upgrade-Insecure-Requests": "1",
    },
    cookies=all_cookie_dict,
    allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)
)

r7_cookie_dict = r7.cookies.get_dict()
all_cookie_dict.update(r7_cookie_dict)
print(r7.headers)


# ######################## 第八步 查看个人信息 #####################
# 控制台点击XHR过滤。XHR英文全名XmlHttpRequest,中文可以解释为可扩展超文本传输请求。
r8 = requests.get(
    url="https://gate.lagou.com/v1/neirong/account/users/0/",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Referer": "https://account.lagou.com/v2/account/userinfo.html",
        "Host": "gate.lagou.com",
        "X-L-REQ-HEADER": "{deviceType:1}",
    },
    cookies=all_cookie_dict
)
# print(r8.text)
"""
{"state":1,"message":"操作成功","content":{"userName":"has222","sex":"MALE",
"portrait":"i/image3/M00/1B/24/CgpOIFp65ICAEqMgAACu8uPNxO0027.png","positionName":"云平台工程师·朗新公司",
"introduce":"Linux运维、python开发","isCompleteInfo":1},"submitCode":"95742353",
"submitToken":"fce637ee-e1ba-46ff-822d-4a3b88ac8478"}
"""
r8_response_json = r8.json()
# print(r8_response_json)
all_cookie_dict.update(r8.cookies.get_dict())


# ######################## 第九步 编辑个人信息 #####################
# 编辑个人信息保存后查看控制台响应
r9 = requests.put(
    url="https://gate.lagou.com/v1/neirong/account/users/0/",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "Host": "gate.lagou.com",
        "Origin": "https://account.lagou.com",
        "Pragma": "no-cache",
        "Referer": "https://account.lagou.com/v2/account/userinfo.html",
        "X-Anit-Forge-Code": r8_response_json.get("submitCode"),
        "X-Anit-Forge-Token": r8_response_json.get("submitToken"),
        "X-L-REQ-HEADER": "{deviceType:1}"
    },
    json={
        'userName': 'hsusu999',
        'sex': 'MALE',
        'portrait': 'i/image3/M00/1B/24/CgpOIFp65ICAEqMgAACu8uPNxO0027.png',
        'positionName': 'python开发工程师;朗xxxxx限公司',
        'introduce': 'Linux运维、python开发',
        'isCompleteInfo': 1
    },
    cookies=all_cookie_dict
)

print(r9.text)
"""
{"state":1,"message":"操作成功","content":{"refreshTgtUrl":"https://passport.lagou.com/refreshTgt/
byUserToken.html?userToken=28e1eae45fa4eef75f0ed1328ef360f415e1e3469dd20ea6&signature=60ACCB0704BD5531C9E7D87673EDAA7E
&action=refreshTgt&callback=https%253A%252F%252Faccount.lagou.com%252Faccount%252Fcuser%252FuserInfo.
html&serviceId=account&ts=1540825857888"},"submitCode":"44415820","submitToken":"74a8c7b0-1851-4f24-8728-73cae1c4763f"}
"""

  个人信息修改结果如下所示:
  

3、拉勾网爬取总结

(1)Token和Code存在页面上,且携带在自定义请求头上

# ############################ 第一步访问登录页面 #################
r1 = requests.get(
    url="https://passport.lagou.com/login/login.html",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
    }
)
# print(r1.text)

"""查看登录页面源码
    <!-- 页面样式 -->    
    <!-- 动态token,防御伪造请求,重复提交 -->
<script>
    window.X_Anti_Forge_Token = '011025d5-fb0e-46be-a2a9-6ad036224062';
    window.X_Anti_Forge_Code = '62107713';
</script>
"""
token = re.findall("X_Anti_Forge_Token = '(.*)';", r1.text)[0]
# print(token)   # '51a18f67-865e-4b8d-9e3f-aad9944611ee'

code = re.findall("X_Anti_Forge_Code = '(.*)';", r1.text)[0]
# print(code)    # '28683037'

(2)重定向:

  如何让requests里面不主动重定向:

allow_redirects=False   # 只往地址发一个请求,不再跳转了(重定向)

  在响应头的Location中获取要重定向的地址:

url=r6.headers["Location"],

(3)请求发送时需要携带上次请求的code和token

 

(4)原则:完全模拟浏览器的行为

  浏览器保存重定向的地址,以下两项需要勾选:

  

六、爬某个人的抖音视频

 

posted @ 2018-10-29 09:37  休耕  阅读(1005)  评论(0编辑  收藏  举报