阶段学习总结之08
day35 Xpath解析器及其应用
- 
 - 
实战案例之爬取猪八戒数据
 
day36 Xpath模块实战与selenuim模块基本使用
- 
爬取城市名称
 - 
爬取猪八戒数据并写入表格
 - 
爬取贴吧图片数据
 - 
自动化测试工具selenuim
 
day37 selenuim进阶操作与大型复杂爬虫案例分析
- 
selenuim其他操作
 - 
图片验证码与滑动验证码的破解思路
 - 
大型复杂爬虫案例讲解
 
day38 B/J爬虫分析
- 
百度自动登录
 - 
爬取京东商品数据
 - 
知乎登录防爬措施
 
详情
day35
- 
解析库之Xpath解析器
Xpath解析器的效率很高,使用广泛,可以使用一条语句完成多步操作。
 
# 使用该解析器需要导入所在的模块 from lxml import etree # 将待匹配文本传入etree生成一个html文件对象 html = etree.HTML(doc)
主要功能
1.匹配所有标签 a = html.xpath('//*') 2.匹配指定标签 eg:匹配所有head标签 a = html.xpath('//head') 3.匹配子标签/后代标签 eg:匹配div标签内的所有儿子a标签 a = html.xpath('//div/a') 匹配body标签内所有后代a标签 a = html.xpath('//body//a') # 这里结果和上面相同 4.匹配父节点 eg:匹配body内部所有href=image1.html的后代a标签 a = html.xpath('//body//a[@href="image1.html"]') 匹配上述标签的父标签 a = html.xpath('//body//a[@href="image1.html"]/..') 5.按索引取值 eg:匹配body内部第一个后代a标签 索引从1开始取值 a = html.xpath('//body//a[1]') 匹配父标签的另一种写法 b = html.xpath('//body//a[1]/parent::*') 6.文本获取(一次性获取,无需循环) eg:匹配body内部所有后代a标签的文本 a = html.xpath('//body//a/text()') 7.属性获取(一次性获取,无需循环) eg:匹配body内部所有后代a标签的href属性值 a = html.xpath('//body//a/@href') eg:匹配title标签的id属性值 a = html.xpath('//title/@id') 8.属性多值匹配(同一属性匹配多个值) 标签有多个类,不能直接匹配,需要使用contains关键字 eg: 匹配body内部所有class=li的后代a标签 a = html.xpath('//body//a[@class="li"]') 匹配body内部所有class包含li的a标签的文本 a = html.xpath('//body//a[contains(@class,"li")]/text()') 9.多属性匹配(同时匹配多个属性) eg:匹配body内部所有class包含li或者name=items的a标签 a = html.xpath('//body//a[contains(@class,"li") or @name="items"]') 匹配body内部所有class包含li并且name=items的a标签的文本 a = html.xpath('//body//a[contains(@class,"li") and @name="items"]/text()') 10.按序选择 eg:匹配最后一个a标签的href属性值 a = html.xpath('//a[last()]/@href') 匹配位置小于3的(前两个) 使用position关键字定位 a = html.xpath('//a[position()<3]/@href') 匹配倒数第三个 a = html.xpath('//a[last()-2]/@href')
了解即可
11.节点轴选择 祖先标签关键字:ancestor eg:匹配所有a标签的所有祖先标签 a = html.xpath('//a/ancestor::*') 匹配所有a标签的祖先标签中的div标签 a = html.xpath('//a/ancestor::*') 12.标签内部所有的属性值 eg:匹配第一个a标签内部所有的属性值 a = html.xpath('//a[1]/attribute::*') 13.标签的儿子标签 eg:匹配第一个a标签所有的儿子标签 a = html.xpath('//a[1]/child::*') 14.所有的后代标签 eg:匹配第六个a标签所有的后代标签 a = html.xpath('//a[6]/descendant::*') 15.当前标签之后的所有标签 eg:匹配第一个a标签之后的所有标签 a = html.xpath('//a[1]/following::*') 匹配第一个a标签之后第一个标签的href属性值 a = html.xpath('//a[1/following::*[1]/@href]') 16.当前标签之后的所有同级标签 eg:匹配第一个a标签之后的所有同级标签 a = html.xpath('//a[1]/following-sibling::*') 匹配第一个a标签之后的所有同级的a标签 # 这里结果同上 a = html.xpath('//a[1]/following-sibling::a') 匹配第一个a标签之后第二个同级标签的文本 a = html.xpath('//a[1]/following-sibling::*[2]/text()') 匹配第一个a标签之后第二个同级标签的href值 a = html.xpath('//a[1]/following-sibling::*[2]/@href')
- 
实战案例之爬取猪八戒数据
 
import requests from bs4 import BeautifulSoup from lxml import etree  res = requests.get('https://shanghai.zbj.com/search/f/', params={'kw': 'python'} ) x_html = etree.HTML(res.text) # 分析标签特征并书写xpath语法筛选 # 1.先查找所有的外部div标签 div_list = x_html.xpath('//div[@class="new-service-wrap"]/div') # 2.循环获取每一个div标签 for div in div_list: price = div.xpath('.//span[@class="price"]/text()') company_name = div.xpath('./div/div/a[1]/div[1]/p/text()') order_num = div.xpath('./div/div/a[2]/div[2]/div[1]/span[2]/text()') info = div.xpath('./div/div/a[2]/div[2]/div[2]/p/text()') print(info)
day36 Xpath模块实战与selenuim模块基本使用
- 
爬取城市名称
 
思路
1、先查看页面加载方式,城市名称是直接加载的。
2、向该页面发送get请求,收到状态码为403的响应,说明该网站有防爬措施。
3、在请求头中加入User-Agent参数模拟浏览器的标识。
4、利用响应内容构造xpath对象。
5、使用xpath,先明确需要查找的标签,往上查找具有一定特征的祖先标签,再逐级往下查找到名称标签,获取城市名称。
6、如果想要获取页面所有城市名称,即同时获取多个标签位置的数据,可以在xpath的参数中写入多条标签路径并用 | 分割。
import requests from lxml import etree  # 1.基础链接 cityUrl = 'https://www.aqistudy.cn/historydata/' # 2.发送请求 cityRes = requests.get(cityUrl, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'} ) # 3.生成xpath对象 cityHtml = etree.HTML(cityRes.text) # 4.获取热门城市名称列表 hotCityList = cityHtml.xpath('//div[@class="hot"]/div[2]/ul/li/a/text()') # print(hotCityList) # 5.获取全部城市名称列表 allCityList = cityHtml.xpath('//div[@class="all"]/div[2]/ul/div[2]/li/a/text()') # print(allCityList) # 6.获取该页面全部城市名称 allCityNames = cityHtml.xpath('//div[@class="hot"]/div[2]/ul/li/a/text() | //div[@class="all"]/div[2]/ul/div[2]/li/a/text()') print(allCityNames)
- 
爬取猪八戒数据并写入表格
 
思路
1、先查看页面加载方式,工作订单内容是直接加载的。
2、向该页面发送get请求
3、利用响应内容构造xpath对象。
4、使用xpath,由于会出现数据混乱,很多时候无法直接查找。
5、需要先明确需要查找的标签,往上查找具有一定特征的祖先标签,再逐级往下找到相关标签,获取工作相关信息。
import requests from lxml import etree from openpyxl import Workbook  # 1.创建Excel表格文件对象 wbWork = Workbook() ws1 = wbWork.create_sheet('工作内容', 0) ws1.append(['公司名称', '地址', '工作内容描述', '订单价格', '历史成交量(近半年)']) def getWork(kw): """ 获取工作相关订单信息 """ # 1.设置网页基本链接 workUrl = 'https://shanghai.zbj.com/search/f' # 2.发送请求获取页面数据 workRes = requests.get(workUrl, params={'kw': kw} ) # 3.生成xpath对象 workHtml = etree.HTML(workRes.text) '''直接查找很多时候是无法使用的 因为会出现数据混乱的现象''' # companyName = workHtml.xpath('//div[@class="new-service-wrap"]/div/div/div/a/div[1]/p/text()') # print(companyName) # 4.先查找所有含有数据的div,再依次循环 divList = workHtml.xpath('//div[@class="new-service-wrap"]/div') # 5.循环工作订单信息 for div in divList: # 6.获取公司名称 companyName = div.xpath('./div/div/a/div[1]/p/text()') # 7.发现有广告位,名称列表存在空值,添加判断 if not companyName: continue # 8.去列表末位去除空格获取公司名称 cName = companyName[-1].strip() # 9.获取公司地址 addressInfo = div.xpath('./div/div/a/div[1]/div/span/text()')[0] # 10.获取订单价格 price = div.xpath('./div/div/a[2]/div[2]/div[1]/span[1]/text()')[0] # 11.获取成交量 amount = div.xpath('./div/div/a[2]/div[2]/div[1]/span[2]/text()')[0].strip('近半年成交:') # 12.工作内容 desc = div.xpath('./div/div/a[2]/div[2]/div[2]/p//text()') # print(''.join(desc)) # 13.添加至Excel表格 ws1.append([cName, addressInfo, ''.join(desc), price, amount])  # 输入搜索关键字 kw = input('请输入工作内容: ').strip() # 调用方法 getWork(kw) wbWork.save('{}工作订单.xlsx'.format(kw))
- 
爬取贴吧图片数据
 
思路
# 分析不同贴吧地址可知:kw参数不同,可以将kw参数作为用户可更改的变量传入 https://tieba.baidu.com/f?ie=utf-8&kw=%E4%B8%83%E9%BE%99%E7%8F%A0&fr=search https://tieba.baidu.com/f?ie=utf-8&kw=%E7%BE%8E%E5%A5%B3&fr=search https://tieba.baidu.com/f?ie=utf-8&kw=%E8%BE%A3%E5%A6%B9&fr=search  1.先获取每个帖子的链接 2.再发送请求 3.在帖子内筛选出图片
完整代码
import time import os import requests from lxml import etree  def getTiebaImg(tName, pageNum): """ 获取贴吧图片 tName: 贴吧名 """ # 1.设置搜索基础地址和贴吧地址 searchUrl = 'https://tieba.baidu.com/f' baseUrl = 'https://tieba.baidu.com' # 2.发送请求 # TODO:多页数据 只需要再加一个pn参数即可 tRes = requests.get(searchUrl, params={'kw': tName, 'pn': (pageNum-1) * 50 } ) # 3.利用响应文本生成xpath对象 tHtml = etree.HTML(tRes.text) # print(tRes.text) # 4.循环帖子链接,拼接成完整地址,再向每个帖子发送请求 aLinkList = tHtml.xpath('//a[@class="j_th_tit "]/@href') for link in aLinkList: fullLink = baseUrl + link # 5.向帖子发送请求 tieRes = requests.get(fullLink) tieHtml = etree.HTML(tieRes.text) # 6.获取图片链接 imgSrcList = tieHtml.xpath('//img[@class="BDE_Image"]/@src') # print(imgSrcList) """主动延迟""" time.sleep(2) for imgSrc in imgSrcList: # 7.向图片地址发送请求 imgRes = requests.get(imgSrc) # 8.拼接文件路径并保存 filePath = os.path.join(tiebaName, imgSrc[-16:]) with open(filePath, 'wb') as f: f.write(imgRes.content) print('{}下载完成'.format(imgSrc[-16:])) """主动延迟""" time.sleep(1)  # 获取用户想要爬取的贴吧名称、页数 tiebaName = input('请输入你想要获得哪个贴吧的图片: ').strip() pn = int(input('请输入你想要搜索的页数: ').strip())  # 判断是否存在名称为当前贴吧名称的文件夹 if not os.path.exists(tiebaName): os.mkdir(tiebaName) # 调用函数 for n in range(1, pn + 1): getTiebaImg(tiebaName, pn)
- 
自动化测试工具selenuim模块
 
selenium原本是一款测试工具,可以操作浏览器,能避免很多防爬措施但是效率慢。
# 1.需要下载第三方模块 pip3 install selenium # 2.需要下载驱动(必备) 该模块用于操作浏览器,针对浏览器需要不同的驱动程序 http://npm.taobao.org/mirrors/chromedriver/2.35/ # 3.存放位置 1.当前编程环境(不推荐) 2.任意位置,需要绝对路径(不推荐) 3.Python解释器的scripts目录中 注意: 有时候下载了驱动可能也无法操作浏览器 原因:可能是因为驱动版本不对 措施:重新一个版本的驱动
测试案例
from selenium import webdriver import time  # 1.指定操作的浏览器驱动(简单粗暴版,不推荐) # 如果找不到,可以手动配置浏览器绝对路径 # options = webdriver.ChromeOptions() # options.binary_location = "C:\Program Files\Google\Chrome\Application\chrome.exe" # bro = webdriver.Chrome(chrome_options=options)  # 1.指定操作的浏览器驱动 bro = webdriver.Chrome() # 2.控制浏览器访问网站 bro.get('https://www.baidu.com') # 3.关闭浏览器 time.sleep(3) bro.close()
基本操作
1、根据id查找网页上的元素 find_element_by_id() eg:divTag = bro.find_element_by_id('s-top-left') 2、根据链接的文本找到a标签 find_elementg_by_link_text() eg:aTag = bro.find_element_by_link_text("新闻") 3、根据链接文本模糊查找a标签 find_element_by_partial_link_text() eg:aTag = bro.find_element_by_partial_link_text("新") 4、根据标签名查找 find_element_by_tag_name 5、根据类名查找 find_element_by_class_name eg:tag = bro.find_element_by_class_name("mnav") 6、根据名称属性查找 find_element_by_name 7、根据CSS选择器查找 find_element_by_css_selector 8、根据xpath查找 find_element_by_xpath
day28 selenuim进阶操作与大型复杂爬虫案例分析
- 
selenuim其他操作
 
1、获取指定标签的属性 tag.get_attribute('href') 2、获取文本内容 tag.text 3、获取标签ID tag.id 获取标签位置 tag.location 获取标签名称 tag.tag_name 获取标签大小 tag.size 4、模拟浏览器后退 browser.back() 模拟浏览器前进 browser.forward() 5、获取cookie browser.get_cookies() 设置cookie browser.add_cookie({'k1': 'xxx', 'k2': 'yyy'}) 6、运行js(括号内为js代码)# 鼠标滚轮移动 bro.execute_script('window.scrollTo(0,200)') 7、选项卡管理 打开一个新网页/选项卡 browser.execute_script('window.open()') 获取所有的选项卡 browser.window_handles 切换指定的选项卡,[]内为选项卡的索引 browser.switch_to_window(browser.window_handles[1])
- 
图片验证码与滑动验证码的破解思路
 
滑动验证码没有破解的必要,不如手动滑效率高
iframe标签:页面上嵌套页面(滑动案例)
# 动作链 from selenium import webdriver from selenium.webdriver import ActionChains import time  driver = webdriver.Chrome() driver.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')  driver.switch_to.frame('iframeResult') # 必须要指定iframe标签 # 起始位置 sourse = driver.find_element_by_id('draggable') # 目标位置 target = driver.find_element_by_id('droppable') # 方式一:基于同一个动作链串行执行(速度太快不合理) # actions = ActionChains(driver) # 拿到动作链对象 # actions.drag_and_drop(sourse, target) # 把动作放到动作链中,准备串行执行 # actions.perform() # 方式二:不同的动作链,每次移动的位移都不同 actions = ActionChains(driver) actions.click_and_hold(sourse) distance = target.location['x'] - sourse.location['x'] track = 0 while track < distance: actions.move_by_offset(xoffset=2, yoffset=0).perform() track += 5 time.sleep(0.5) actions.release()  driver.close()
无界面操作
from selenium.webdriver.chrome.options import Options chrome_options = Options() # 添加相关参数即可实现无界面操作 chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') bro = webdriver.Chrome(chrome_options=chrome_options) bro.get('https://www.baidu.com') # 如何获取页面html代码 driver.page_source '''可以去药品许可证界面尝试'''
针对selenuim防爬机制
# 很多程序是可以分辨出来当前浏览器是否被selenuim操作 我们可以在代码中添加如下配置即可避免被识别 from selenium.webdriver import ChromeOptions option = ChromeOptions() option.add_experimental_option('excludeSwitchers',['enable-automation']) bro = webdriver.Chrome(options=option)
图片验证码
# 解决方法 1、完全使用代码破解 全自动,一步到位 2、打码平台(第三方服务) 其实这类第三方服务一般也是先使用代码识别,不行就员工自己看。 3、自己看 可以事先利用代码预留肉眼识别并输入验证码的时间
- 
大型复杂爬虫案例讲解
 
cookie登录(以博客园为例)
思路:1、通过seleuinm拿cookie。 2、使用requests模块携带cookie去模拟爬取数据。
import requests from selenium import webdriver import time import json  """ 使用selenium打开登录界面的网址,然后让用户完成手工登录,再获取cookie """ url = 'https://account.cnblogs.com/signin?returnUrl=https:%2F%2Fwww.cnblogs.com%2F' driver = webdriver.Chrome() driver.get(url=url) time.sleep(30) # 预留时间让用户输入用户名和密码 driver.refresh() # 获取登录成功之后服务端发回的cookie数据 cookiesB = driver.get_cookies # 保存获得的cookie with open('boKeYuan.txt', 'w') as f: json.dump(c, f) """ 处理获得的cookie """ cookies = {} with open('boKeYuan.txt', 'r') as f: di = json.load(f) # 获取cookie中的name和value,转化成requests可以使用的形式 for cookie in di: cookies[cookie['name']] = cookie['value'] print(cookies) """ 使用该cookie完成请求 """ response = requests.get(url='https://i-beta.cnblogs.com/api/user', cookies=cookies) response.encoding = response.apparent_encoding print(response.text)
一、B站视频案例
b站有很多视频是一分为二的,分为视频(只有画面没有声音)和音频(只有与视频配套的声音)。
教学文档
1、下载单个视频文件与音频文件
https://www.cnblogs.com/xiaoyuanqujing/articles/12016934.html
2、批量下载页面上的视频与音频并合并 https://www.cnblogs.com/xiaoyuanqujing/articles/12014416.html
二、红薯网小说案例
目标网页
https://www.hongshu.com/content/3052/3317-98805.html
教学文档
https://www.cnblogs.com/wyhb/p/15353266.html
# 主要思路分析 1.小说详情页面鼠标左右键全部禁用 但是支持按F12调出控制台 2.小说文字不是直接加载 查找相关二次请求 3.在请求中发现可疑数据 https://www.hongshu.com/bookajax.do content:加密数据 other:加密数据 bid: 3052 jid: 3317 cid: 98805 4.文字内容的解密过程发送在浏览器本地 涉及到数据解密肯定需要写js代码 并且一般都会出现关键字decrypt 通过浏览器查找相应的js代码 文字主要内容的界面 utf8to16(hs_decrypt(base64decode(data.content), key)) 解密之后仍然存在数据缺失的情况 utf8to16(hs_decrypt(base64decode(data.other), key)) 解密之后是一段js代码 # 怀疑缺失的数据与解析出来js代码有很大的关系 5.自己新建一个html文件 将content内部拷贝只body内 将js代码引入到该html文件夹
day38 B/J爬虫分析
- 
百度自动登录
 
1、用户名密码登录
from selenium import webdriver import time  # 1.指定操作的浏览器驱动(谷歌) bro = webdriver.Chrome() # 2.控制浏览器访问网站 bro.get('https://www.baidu.com')  # 3.获取登录链接标签 loginTag = bro.find_element_by_id('s-top-loginbtn') # 4.点击登录链接 loginTag.click() # 5.一般弹出窗口都是悬浮窗口 # 该页面登录框不是由悬浮窗口构成,这里直接查找即可 # bro.switch_to.frame('iframeResult') '''延迟等待:页面数据有时候需要时间加载 但是代码不会自动等''' time.sleep(3) # 6.获取用户名以及密码输入框 userName = bro.find_element_by_id('TANGRAM__PSP_11__userName') password = bro.find_element_by_id('TANGRAM__PSP_11__password') # 7.书写用户名和密码 userName.send_keys('正确的用户名') password.send_keys('正确的密码') # 8.获取登录按钮 loginBtn = bro.find_element_by_id('TANGRAM__PSP_11__submit') # 9.点击登录按钮 loginBtn.click() # 10.延迟并关闭 time.sleep(15) bro.close()
2、短信验证码登录
from selenium import webdriver import time  # 1.使用谷歌浏览器访问百度首页 bro = webdriver.Chrome() bro.get('https://www.baidu.com/') # 2.查找页面上的登录按钮 login_tag = bro.find_element_by_id('s-top-loginbtn') # 3.点击登录按钮 time.sleep(0.5) login_tag.click() time.sleep(3) # 4.查找点击短信登录按钮 message_tag = bro.find_element_by_id('TANGRAM__PSP_11__changeSmsCodeItem') message_tag.click() time.sleep(0.5) # 5.查找手机号输入框并填写内容 phone_tag = bro.find_element_by_id('TANGRAM__PSP_11__smsPhone') phone_tag.send_keys(18818188888) time.sleep(0.5) # 6.查找发送验证码按钮并点击 btn_tag = bro.find_element_by_id('TANGRAM__PSP_11__smsTimer') btn_tag.click() time.sleep(0.5) # 7.查找并点击登录按钮 submit_tag = bro.find_element_by_id('TANGRAM__PSP_11__smsSubmit') submit_tag.click() time.sleep(0.5) # 8.关闭浏览器 bro.close()
延时等待
访问百度时在登录框弹出前就查找按钮会因为找不到而报错, 各种网站的加载都需要时间,导致代码容易报错。此时我们需要在等待页面数据加载完毕后继续执行代码,可以加入以下语句。
# 加在指定浏览器驱动的语句后 bro.implicitly_wait(10)
- 
爬取京东商品数据
 
注意点
1.商品数据的展示页存在动态加载的情况 需要往下滚动 # 当前页面屏幕高度 window.document.body.scrollHeight # 滚动到指定位置 window.scrollTo 2.针对图片数据存在懒加载现象 3.多页数据的爬取 由于我们使用的是selenuim所以此处只需要查找下一页按钮点击即可 将单页爬取数据的代码封装成一个函数 之后就可以循环爬取多页 4.数据的持久化(保存)
完整代码
import time  from selenium import webdriver from selenium.webdriver.common.keys import Keys  bro = webdriver.Chrome() # 1.访问京东首页 bro.get('https://www.jd.com/') bro.implicitly_wait(10) # 延时等待 # 2.查找搜索款并输入商品名称 search_input = bro.find_element_by_id('key') search_input.send_keys('高达') # 3.按下enter键进入商品展示页 search_input.send_keys(Keys.ENTER)  # 由于数据存在滚动加载的现象 for i in range(0, 8000, 1000): # 千万不能直接到底 一定要有一个波段 bro.execute_script('window.scrollTo(0,%s)' % i) time.sleep(0.5)  good_list = bro.find_elements_by_css_selector('li.gl-item') # 循环获取每一个li标签 筛选所需数据 for li in good_list: # 图标标签的src属性 img_tag = li.find_element_by_css_selector('div.p-img a img') img_src = img_tag.get_attribute('src') '''img标签的src属性存在懒加载现象 src没有就在data-lazy-img属性下''' if not img_src: img_src = 'https:' + img_tag.get_attribute('data-lazy-img') # 商品价格 price_tag = li.find_element_by_css_selector('div.p-price strong') order_price = price_tag.text # 商品描述 desc_tag = li.find_element_by_css_selector('div.p-name a em') order_desc = desc_tag.text # 商品链接 link_tag = li.find_element_by_css_selector('div.p-name a') order_link = link_tag.get_attribute('href') # 商品销量 commit_tag = li.find_element_by_css_selector('div.p-commit strong a') order_commit = commit_tag.text # 店铺名称 shop_tag = li.find_element_by_css_selector('div.p-shop span a') shop_name = shop_tag.text # 店铺链接 shop_link = shop_tag.get_attribute('href') # 通过打印展示数据 也可以数据持久化到表格文件 print(""" 商品描述:%s 商品价格:%s 商品图片:%s 商品链接:%s 店铺名称:%s 店铺链接:%s """ % (order_desc, order_price, img_src, order_link, shop_name, shop_link)) # 关闭浏览器 bro.close()
- 
知乎登录防爬措施
 
1.电脑端知乎不登陆是无法直接访问首页的 2.network监控发送登录请求体数据为加密 加密的代码关键字:encrypt 解密的代码关键字:decrypt 3.搜索关键字encrypt通过断点调试查看到加密数据 4.运行解密相关JS代码,分析数据 5.获取真实的请求体数据,发送请求获取数据
                    
                
                
            
        
浙公网安备 33010602011771号