爬虫实战3(模拟登陆知乎并爬取任意帖子数据)

? ?
?? 刚学爬虫时,看到一篇文章硬核破解知乎登陆,心潮澎湃,真男人!符合我的胃口!哼哧哼哧的立刻安排!
??(半个小时过后)
??似乎我是弱智?很多看不懂?(百度乱搜中…)恩还有种简单的?selenium+xpath模拟登陆?简单但效率低?难道要靠用这种低效率方式来爬取数据,这是向网站妥协!不,我常威就算没技术也绝对不要这样委屈求全!(十分钟过后)挨,怎么他喵这么香?
?? 经过一番曲折的故事(中间花了半个月拿了几个小项目练练手),终于进入激动人心的实战,马上就可以 爬取知乎姑娘的美照 学到新知识了!本文行文结构如下:
? ?1. 做好准备了吗
? ?2. selenium+xpath模拟登陆知乎获取cookies
? ?3. request+re+json+jsonpath 爬取知乎指定问题下所有回答数据(照片)
? ?4. 进行面对对象重新构造
? ?5. 总结
?
0、 做好准备了吗 ?

  • selenium 安装配置教程
    ?
    ? selenium及相应环境驱动配置安装,请查看:
    ? ? selenium及驱动器安装配置教程详解
    ?
  • 什么是selenium
    ?
    ? ?不知道大家有没有用过按键精灵的API,用这套API我们就可以进行点击、输入等一系列模拟真实用户操作。selenium和其类似,只不过它可直接作用于浏览器,模拟打开、进行点击,输入等操作。用它可以很方便避开反爬机制,拿到我们要的界面源码进而获取数据,但是缺点速度太慢。
    ? 了解更多:
    ? ? Python爬虫利器五之Selenium的用法
    ? ? Python 爬虫基础Selenium库的使用
    ?
  • 什么是xpath
    ?
    ? ?前面我们介绍过正则表达式和相应re模块,在网页上定位元素,获取数据re模块当然也可以做到但是过于繁琐。
? ?? ?? ? XPath 是一门在 XML 文档中查找信息的语言,用来在网页XML 文档中对元素和属性进行遍历,语法简单方便。
?安装及了解更多:
? ? Python爬虫利器三之Xpath语法与lxml库的用法
?
  • json与jsonpath
    ?
    ? ?json(JavaScript Object Notation)是一种轻量级的数据交换格式,具有数据格式简单,读写方便易懂等优点,相对于XML来说,更加的轻量级,更方便解析,因此许多开发者都遵循json格式来进行数据的传输和交换。比如我们后面获取到的cookie和利用知乎API获取的回答信息都是json格式。
    ? ? jsonpath之于json 便如xptah之于XML,是专门用来解析json数据格式的模块,语法简洁比直接调用re模块正则解析方便。
    ?安装及了解更多:
    ? ? JSON入门教程
    ? ? json解析神器 jsonpath的使用
    ?
一、模拟登陆知乎 ?
正如前言,模拟登陆知乎,有两种思路:
  • request硬核破解:
    知乎对Form Date数据进行了加密,要抓包分析同时对JavaScript有一定了解才能尝试分析出来。
    可参阅:模拟登陆知乎
  • selenium模拟登陆:
    模拟真实打开浏览器登陆,拿到cookies,再用request爬取数据,难度较低,可操作性强。
    这里我们采用第二种方式。
    ?
1.1 开始模拟登陆1:QQ模拟登陆
?
? ?模拟登陆有多种方式,使用知乎登陆界面提供的QQ号登陆可以避免验证码,进而获取cookies。另外一种便是使用手机号登陆,需要验证码,将在1.2 详细讲述。
?
  • 引入模块
    ?
    from selenium import webdriver from base64 import b64decode# 解码验证码b64编码,QQ登陆不用 import time# 用于暂停,防止被检测 import json# 保存json格式cookies,便于读取 import os# 主要用于创建文件夹等操作

  • 打开浏览器
    ?
    # 1.打开浏览器 browser = webdriver.Chrome() browser.get('http://www.zhihu.com')

    执行这段代码,便会看到程序自动打开Chrome浏览器,进入到知乎登陆界面。
    ?
  • 找到QQ登陆按钮
    ?
    # 2.找到QQ登陆按钮 # 先找到登陆按钮 bt_opt_login = browser.find_element_by_xpath('//div[@class="SignContainer-switch"]/span') bt_opt_login .click() # 再选择社交账号方式登陆 bt_opt_social = browser.find_element_by_xpath('//span[@class="Login-socialLogin"]/button') bt_opt_social.click() time.sleep(1)# 等等QQ登陆图标加载一下 # 最后点击QQ图标登陆 bt_opt_QQ = browser.find_element_by_xpath('//span[@class="Login-socialButtonGroup"]/button[3]') bt_opt_QQ.click() time.sleep(1)# 等待下加载完毕

    注意,最后一步选择QQ图标登陆按钮时,大家可以看到,其在一对标签所中:
    ? 爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ?
    ? 如果大家直接xpath定位到g标签中:
    //svg[@class="Icon Login-socialIcon Icon--qq"]/g

    ? 是不能定位成功的,定位svg元素要用xpath的name()函数,且自svg以下都要用:*[name()='svg element']这种形式
    //span[@class="Login-socialButtonGroup"]/button[3]/*[name()='svg']/*[name()='g']

    ? 也可以像上面,更简洁的直接定位到button[3]按钮标签即可(第三个是QQ登陆按钮)。
    ?
  • 切换到内置QQ登陆窗口登陆
    ?
    点击QQ图标选择登陆后,便会弹出一个内嵌QQ登陆子网页。自然而然,我们要切换窗口:
    # 3.操作刚打开的QQ登陆界面 # 切换到qq登陆界面句柄 allhandles = browser.window_handles zhihuHandle = browser.current_window_handle qqHandle = allhandles[1] # qq登陆内嵌页面要切换表单 browser.switch_to.frame("ptlogin_iframe")

    ? ? browser.window_handles 获取当前所有窗口句柄,第一个是知乎窗口,第二个自然是QQ登陆窗口。但是要提醒大家的是,QQ登陆是内嵌QQ登陆子网页,还需要切换表单frame,切换表单需要知道表单名,那么问题来了,如何找到当前QQ登陆子网页表单名?
    ? ?F12>>分析网页元素,ctrl+shift+f 打开搜索框,输入frame搜索,可以找到frame_name = ptlogin_iframe,复制进行切换表单。
    ? 爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ?
    ? ? 接下来,就是模拟输入账号密码点击登陆了,距离成功登陆只差一点点啦!接下来的代码也清晰易懂,主要就是定位元素,这里xpath定位不太方便,直接查找id会更方便点。
    # 选择输入密码登陆 bt_opt_inputAP = browser.find_element_by_xpath('//div[@id="bottom_qlogin"]') bt_opt_inputAP.click() # 开始模拟输入账号密码登陆 text_qq_account = browser.find_element_by_id("u") text_qq_password = browser.find_element_by_id("p") bt_qq_login = browser.find_element_by_id("login_button") text_qq_account.send_keys("380141***")# 输入你的QQ账号 text_qq_password.send_keys("riguangyu******")# 输入你的QQ密码 bt_qq_login.click() time.sleep(3)

    ? ?最后大家不要忘了,切回知乎主窗口,表单不用切换。
    # 切回知乎窗口,表单不用 browser.switch_to.window(zhihuHandle)

    ?
  • 保存cookie
    ? 终于进入到知乎首页了,距离爬取好看的姑娘美照,啊不对更进一步学习更近了,哈哈~大家不要忘了我们辛苦模拟登陆就是为了拿到cookie,迫不及待来看看怎么保存cookie吧。
zhihu_cookies = browser.get_cookies()

? ? hh,获取cookie还是还简单的,返回的zhihu_cookies是一个字典类型。但是现在问题来了,如果我们直接将它写入txt文档,读取的时候是string类型,不再是字典,这样就很不方便读取里面数据了,总不然正则分析吧?
? ? 这个时候json就闪亮登场了,我们用json.dumps将cookie转为json格式写入txt,读取的时候再用json.load方法读取,返回的就又是字典类型了。进一步了解,参照前: JSON入门教程
4.selenium保存cookie保存 zhihu_cookies = browser.get_cookies() json_cookies = json.dumps(zhihu_cookies) with open("C:\\Users\\86151\\Desktop\\json_cookies.txt", "w") as f: f.write(json_cookies)

? ? 让我们看看txt里都写入了啥:
爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
文章图片

? ?嗷嗷,就是一个列表嘛,里面每一项又是字典。记住这个形式,方便后面我们理解读取cookie。
?
1.2 开始模拟登陆2:手机号模拟登陆
?
? ?前面虽然已经详细记录QQ模拟过程,但是我还是想记录下手机号登陆过程,因为这种登陆方式,必不可免的遇到处理验证码。如何处理验证码是学爬虫绕不过的坎,要撞的南墙。这里我将重点记录处理知乎验证的过程。如果迫不及待想看美羊羊洗澡,哦不小姐姐美照的同学可以略过这节。
?
  • 基本操作
    ?
    前面登陆过程和QQ登陆大同小异,这里直接给出代码供大家参考。
    from selenium import webdriver from base64 import b64decode# 解码验证码b64编码,QQ登陆不用 import time# 用于暂停,防止被检测 import json# 保存json格式cookies,便于读取 import os# 主要用于创建文件夹等操作count = 0 while 1: # 1.打开浏览器 # browser = webdriver.Chrome(chrome_options=chromeOptions) browser = webdriver.Chrome() browser.get('http://www.zhihu.com')# 2.输入账号密码 # 1.点击登陆 bt_opt_login = browser.find_element_by_xpath('//div[@class="SignContainer-switch"]/span') bt_opt_login .click() time.sleep(1) # 2.输入账号密码 # elem_account = browser.find_element_by_name("username") # elem_pwd = browser.find_element_by_name("password") text_account = browser.find_element_by_xpath('//input[@name="username"]') text__pwd = browser.find_element_by_xpath('//input[@name="password"]') text_account.send_keys("1517948****") text__pwd.send_keys("riguangyu******")# 3.模拟点击登陆 bt_login = browser.find_element_by_xpath('//button[@type="submit"]') bt_login.click()

    ? ? 我们输入完手机号&密码点击登陆,本小节重点验证码boss便出现了,欲知我如何和验证码斗智斗勇大战三百回合且听下步分解。
    ?
  • 处理验证码
    ?
    ? 知乎的验证码有两种,一种是还算人性化英文验证码:
    ?
    爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    一种便是毫无人性的中文验证码,要求我们点击图中倒立的中文字符:
    ?
    爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ? ? 中文验证码是比较难以处理的,我对它的处理方式就是:不处理~hh,简单来说,判断出现中文验证码就刷新界面,直至出现英文验证码开始输入验证码登陆。
    ? ?那么问题又来了(废宅就是问题多hh),如何判断出现中文字符?首先,直接定位中文验证码元素,如何定位不成功报错,说明出现的是英文验证码。捕获异常进行处理英文验证码即可。
    # 4.处理验证码登陆 # 4.1 获取英文验证码图片 time.sleep(1)# 等待一会儿验证码图片还没加载 # noinspection PyBroadException try: img_captcha = browser.find_element_by_class_name("Captcha-chineseImg")# 定位到图片元素| "Captcha-englishImg" count += 1 print("中文字符暂时不能处理,第{0}次重试...\n".format(count)) browser.close() time.sleep(1) continue except Exception as e: img_captcha = browser.find_element_by_class_name("Captcha-englishImg") img64_src = https://www.it610.com/article/img_captcha.get_attribute("src")# 获取验证码b64编码 img64_src = https://www.it610.com/article/img64_src.replace("data:image/jpg; base64,", "")# 删除前面标识 img64_src = https://www.it610.com/article/img64_src.replace("%0A", "\n")# get_attribute会把\n替换成%OA,要替换回来 img_date = b64decode(img64_src)

    ? ?大家可能会对验证码b64编码处理,这段代码有所疑问。
    1. 验证码是服务器自动生成的,不是给URL地址,而是一串b64编码字符,我们对它进行解码处理。可以看到下面这张图片,验证码b64编码见下:
      ? 爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
      文章图片

      ?
    2. 特别注意get_attribute这个方法会把\n替换成%OA,要替换回来
    ?处理好验证码,我们可以把它保存在本地,然后打开,这样我们只要手工输入验证码就可以登录了。
    # 4.2 保存图片 img_path = captcha_savePath + "\\captcha.png" with open(img_path, "wb") as f:# 将验证码图片以二进制流写入保存 f.write(img_date) # 4.3 打开图片 os.system(img_path) captcha = input("已捕捉到英文验证码,请在打开的图片识别输入:") time.sleep(2) # 4.4 输入验证码登陆 elem_captcha_input = browser.find_element_by_xpath('//input[@name="captcha"]') elem_captcha_input.send_keys(captcha) # 4.5 登陆 bt_login1 = browser.find_element_by_xpath('//button[@type="submit"]') bt_login1.click() time.sleep(2)

    爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    验证码处理完毕便可以登录到知乎首页了,同1.1接下来保存cookie即可。
    ?
  • 保存cookie
    ?
    # 5.保存cookie zhihu_cookies = browser.get_cookies() json_cookies = json.dumps(zhihu_cookies) with open("C:\\Users\\86151\\Desktop\\json_cookies.txt", "w") as f: f.write(json_cookies)

    ?
二、爬取知乎数据 ?
? ?拿到cookie后我们又要掏出我们的老伙计------requests来爬取数据了。只要在requests请求时带上cookie参数,我们便可以相当于输入账号密码验证过身份直接登陆知乎了。
? ? 我们表面随便(预谋已久)拿知乎某著名相亲贴爬取下面回答姑娘的照片来试试手:你的择偶标准是怎样的
?
  • 分析网站请求
    ?
    爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ?
    ? ? 我们可以看到,知乎回答只有往下滑动才能加载出更多。而知乎URL一直没有变化,想直接简单观察构造URL是行不通了。
    ? ?难道就这么放弃吗?我们爬虫,哦不,程序员绝不轻易认输!F12 分析网页元素,点击XHR窥屏网站请求(XHR类型即通过XMLHttpRequest方法发送的请求,知乎要请求加载回答)。然后,我们开始滑动,往下加载回答,看看都有什么请求。
    ? ?报告!发现可疑分子!收到~~让我们看看到底是何方神圣:
    ? 爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ?
    ? ?这个answer开头请求显然是非常可疑的,点进去窥视一下,发现有一大串的URL,复制过来我们把它粘贴过来打开浏览器访问(这里复制到firefox打开会自动转成json格式便于查看):
    ? 爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ?
    ? ?果不其然,这里就是请求的回答信息,服务器返回json格式。后来查阅了一下,没想到是知乎开放的API,我常威是靠某乎施舍…各位看官老爷,咋这就赶紧麻溜开始吧。上上张图片已经分析出下面这一大串URL规律:
    limt: 限制一次请求回答数,经过测试可以改为20,即一次请求20条回答。
    offset:偏移量,前面已有回答数。
    其余无变化。
    ? ? 明白了知乎是怎么请求了,接下来只要构造request请求,会jsonpath对知乎API返回的json数据进行处理,就可以愉快的爬下我们想要的数据了(你明白的)。
    ?
  • 读取cookie构造request请求
    ?
    ? ?正如前cookie所说的格式,是一个列表,每一项是字典。每一个字典里有很多键值对,我们只需每个字典都有的键name&value对应的值(其余的键值不用,这两个就够了),构造成一个新的 name值:value值对应的新cookie字典。
    # 5.读取cookies cookies_dic = {} with open("C:\\Users\\86151\\Desktop\\json_cookies.txt", "r") as f: cookies = json.load(f) # 在保存的cookies文档中,一个列表,每一项都是字典,字典又自然有多个键值对。只有每一个字典键值name,value对应的数据需要记住 for cookie in cookies: cookies_dic[cookie['name']] = cookie['value']

    ? ? 然后再传入headers伪装浏览器,循环构造URL请求进行请求即可。
    # 6.分析知乎帖子,正则匹配获取每篇答案的作者/赞同数/图片等信息 desktop_path = "C:\\Users\\86151\\Desktop" headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"} answer_url = "https://www.zhihu.com/api/v4/questions/275359100/answers?include=data%5B%2A%5D.is_normal%2Cadmin_closed_comment%2Creward_info%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelevant_info%2Cquestion%2Cexcerpt%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cis_labeled%2Cis_recognized%2Cpaid_info%3Bdata%5B%2A%5D.mark_infos%5B%2A%5D.url%3Bdata%5B%2A%5D.author.follower_count%2Cbadge%5B%2A%5D.topics&limit=20&offset={0}&platform=desktop&sort_by=default" # 爬十次,每次爬20篇回答,共200篇 for i in range(10): dest_url = answer_url.format(i*20) response = requests.get(dest_url, headers=headers, cookies=cookies_dic)

    ? ?接下来,我们便开始用jsonpath解析获取的数据
    ?
  • jsonpath解析数据
    ?
    ? ? 首先当然是用json.load加载读取到的数据,接着便是简单运用jsonpath对json数据进行解析:
    # 爬取的是json格式,要读取分析用json.loads载入 json_date = json.loads(response.text) # 保存这20篇回答:作者 & 回答内容 authors = jsonpath.jsonpath(json_date, '$..author.name') contents = jsonpath.jsonpath(json_date, '$..content')

    ? ? 那么问题还是他喵又来了,回答里包含照片的URL地址信息,如何获得呢?jsonpath 和xpath肯定是不行的,什么你已经想到了?没错就是正则表达式(主要还是我睿智分析)!
    ? ?首先我们点开任意一个回答,看看照片深藏在哪个金屋中:
    ? 爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ?
    ? ? 令人窒息的是,同一张照片URL既可能出现在爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    爬虫实战3(模拟登陆知乎并爬取任意帖子数据)
    文章图片

    ? ? 这里我们发现了一点小瑕疵,有些图片下载失败,经过排查URL请求是正确的,单独下载也能成功,某些不可描述因素?后续如果解决,会进行更新~
    ? ?至此,知乎爬虫便基本制作成功了,接下来就是进行面对对象的重构,以及此次项目总结一些善后工作了。
?
三、面对对象重构 ?
from selenium import webdriver from base64 import b64decode import requests import re import time import json import jsonpath import osclass zhihuSpider:def __init__(self): # 初始化headers、登陆界面url、 self.loginURL = "http://www.zhihu.com" self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}def zhihu_qq_login(self, account, password): """ :param account: 账号 :param password: 密码 :return: 尝试qq登陆,返回只含有键值name,value对应字典cookie """ # 1.打开浏览器 browser = webdriver.Chrome() browser.get(self.loginURL)# 2.查找登陆元素 # 点击登陆 # 因为'登陆'在一对登陆标签中,但是没有元素属性不好精确定位,采用XPATH语法 bt_opt_login = browser.find_element_by_xpath('//div[@class="SignContainer-switch"]/span') bt_opt_login.click() # 选择QQ号登陆 bt_opt_social = browser.find_element_by_xpath('//span[@class="Login-socialLogin"]/button') bt_opt_social.click() time.sleep(1)# 等等QQ登陆图标加载一下 bt_opt_QQ = browser.find_element_by_xpath('//span[@class="Login-socialButtonGroup"]/button[3]') bt_opt_QQ.click()# 3.操作刚打开的QQ登陆窗口 time.sleep(1)# 等待下加载完毕 # 切换到qq登陆窗口 allhandles = browser.window_handles zhihuHandle = browser.current_window_handle qqHandle = allhandles[1] browser.switch_to.window(qqHandle) # 同时qq登陆内嵌页面要切换表单:ctrl+shift+f搜索:frame,找到frame name = ptlogin_iframe browser.switch_to.frame("ptlogin_iframe") # 选择输入密码登陆 bt_opt_inputAP = browser.find_element_by_xpath('//div[@id="bottom_qlogin"]') bt_opt_inputAP.click() # 开始模拟输入账号密码登陆 text_qq_account = browser.find_element_by_id("u") text_qq_password = browser.find_element_by_id("p") bt_qq_login = browser.find_element_by_id("login_button") text_qq_account.send_keys(account) text_qq_password.send_keys(password) bt_qq_login.click() time.sleep(3) # 切回知乎窗口,表单不用 browser.switch_to.window(zhihuHandle) # 4.返回含指定键值的cookie字典 # zhihucookie是列表含有多项,每项都是字典类型; 这里不用txt保存,故无需解析成json数据 zhihu_cookies = browser.get_cookies() cookies_dic = {}# 只保存键值name,value对应的数据 for cookie in zhihu_cookies: cookies_dic[cookie['name']] = cookie['value'] browser.close() return cookies_dicdef zhihu_phoneNum_login(self, account, password, captcha_savePath): """ 循环模拟登陆知乎,直至出现的是英文验证码,输入验证码登陆 :param account: 账号 :param password: 密码 :return: 尝试手机号登陆,返回只含有键值name,value对应字典cookie """ count = 0 while 1: # 1.打开浏览器 browser = webdriver.Chrome() browser.get('http://www.zhihu.com') # 2.查找登陆元素 # 1.点击登陆 bt_opt_login = browser.find_element_by_xpath('//div[@class="SignContainer-switch"]/span') bt_opt_login.click()# 2.输入账号密码 time.sleep(1) # elem_account = browser.find_element_by_name("username") # elem_pwd = browser.find_element_by_name("password") text_account = browser.find_element_by_xpath('//input[@name="username"]') text__pwd = browser.find_element_by_xpath('//input[@name="password"]') text_account.send_keys(account) text__pwd.send_keys(password)# 3.模拟点击登陆 bt_login = browser.find_element_by_xpath('//button[@type="submit"]') bt_login.click()# 4.处理验证码登陆 # 1.获取验证码图片 time.sleep(1)# 等待一会儿验证码图片还没加载 # noinspection PyBroadException try: # 定位到中文验证码,刷新浏览器重新登陆。 img_captcha = browser.find_element_by_class_name("Captcha-chineseImg") print("中文字符暂时不能处理,第{0}次重试...\n".format(count + 1)) browser.refresh() time.sleep(1) continue except Exception as e: # 定位中文验证码出错,则说明定位到英文验证码,开始识别人工输入 # 验证码是服务器生成b64编码,直接进行解码写入保存即可,不用下载 # 定位到验证码元素 img_captcha = browser.find_element_by_class_name("Captcha-englishImg") # 获取元素内的验证码b64编码 img64_src = https://www.it610.com/article/img_captcha.get_attribute("src") # 对编码进行一些处理可解码 img64_src = https://www.it610.com/article/img64_src.replace("data:image/jpg; base64,", "")# 删除前面标识 img64_src = https://www.it610.com/article/img64_src.replace("%0A", "\n")# get_attribute会把\n替换成%OA,要替换回来 img_date = b64decode(img64_src) # 2.保存图片 img_path = captcha_savePath + "\\captcha.png" with open(img_path, "wb") as f:# 将验证码图片以二进制流写入保存 f.write(img_date) # 3.打开图片 os.system(img_path) captcha = input("已捕捉到英文验证码,请在打开的图片识别输入:") time.sleep(2) # 4. 输入验证码登陆 elem_captcha_input = browser.find_element_by_xpath('//input[@name="captcha"]') elem_captcha_input.send_keys(captcha) # 5.登陆 bt_login1 = browser.find_element_by_xpath('//button[@type="submit"]') bt_login1.click() time.sleep(2)# 5.已经成功登陆,返回含指定键值的cookie字典 # zhihucookie是列表含有多项,每项都是字典类型; 这里不用txt保存,故无需解析成json数据 print("成功登陆!即将开始下载...") zhihu_cookies = browser.get_cookies() cookies_dic = {}# 只保存键值name,value对应的数据 for cookie in zhihu_cookies: cookies_dic[cookie['name']] = cookie['value'] browser.close() return cookies_dicdef download(self, cookies_dic, answer_url, img_savepath, pages, limit=20): """ 下载知乎指定任意问题下图片 :param cookies_dic: 知乎cookie :param answer_url: 知乎问题url :param img_savepath: 知乎问题下图片保存路径 :param pages: 下载多少页 :param limit: 一页默认限定20篇回答 :return: """ # 爬十页,每页爬20篇回答,共200篇 for p in range(pages): dest_url = answer_url.format(limit, p * limit) response = requests.get(dest_url, headers=self.headers, cookies=cookies_dic) # 爬取的是json格式,要读取分析用json.loads载入 json_date = json.loads(response.text) # 保存这20篇回答:作者、答案中图片 authors = jsonpath.jsonpath(json_date, '$..author.name') contents = jsonpath.jsonpath(json_date, '$..content') # 循环在指定root_path创建以作者名命名的文件夹,里面放有相应回答照片 for l in range(limit): # 创建以作者名命名的文件夹 author_path = img_savepath + "\\知乎照片1\\" + authors[l] if not os.path.exists(author_path): os.makedirs(author_path) # 用re正则解析对应的回答内容里面的图片 img_pattern = re.compile('data-original="(.*?)"') img_urls = re.findall(img_pattern, contents[l])# 相邻两个重复 new_img_urls = [] index = 0 # url相邻重复,去除 for url in img_urls: if index % 2 == 0: new_img_urls.append(url) index += 1 # 判断是否有图片 if len(new_img_urls) == 0: print("无照片") continue # 下载图片 count = 0 for url in new_img_urls: img_path = author_path + "\\" + str(count) + ".jpg" response_img = requests.get(url) with open(img_path, "wb") as f: f.write(response_img.content) count += 1 print("第{0}篇回答照片下载完毕".format(p * limit + l + 1)) time.sleep(5)# 等待5s,开始下载下一页 print("下载完毕!")if __name__ == '__main__': answer_url = "https://www.zhihu.com/api/v4/questions/275359100/answers?include=data%5B%2A%5D.is_normal%2Cadmin_closed_comment%2Creward_info%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelevant_info%2Cquestion%2Cexcerpt%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cis_labeled%2Cis_recognized%2Cpaid_info%3Bdata%5B%2A%5D.mark_infos%5B%2A%5D.url%3Bdata%5B%2A%5D.author.follower_count%2Cbadge%5B%2A%5D.topics&limit={0}&offset={1}&platform=desktop&sort_by=default" desktop_path = "C:\\Users\\86151\\Desktop" spider = zhihuSpider() # cookies_dir = spider.zhihu_qq_login("380141****", "riguangyu*****") cookies_dir = spider.zhihu_phoneNum_login("1517948****", "riguangyu***", desktop_path) spider.download(cookies_dir, answer_url, desktop_path, 10)

?
四、总结 ?
? ?呼呼,终于完成了!最开始接触爬虫,便想着爬取知乎小姐姐照片,成功的那一刻还是挺有成就感的。下一篇博文便是记录破解bilibili滑块验证码了,你滑任你滑,我爬我的虫~
【爬虫实战3(模拟登陆知乎并爬取任意帖子数据)】? ?下次再见啦!对了,俺也不是要求太多,这么详细的知乎爬虫记录,各位看官老爷不点个关注/喜欢嘛?谢谢您的鼓励~

    推荐阅读