1,Selenium
1.1,Selenium安装
实际动态网页中,很多Ajax请求的参数是加密的,用户很难通过分析Ajax请求获取真实的URL,还有一些动态加载数据并不是Ajax生成的从,此时,可以使用Selenium模拟浏览器的方法来获取网页动态加载和渲染的数据。
Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作。同时还可以获取浏览器当前呈现的页面内容,做到可见即可爬。Python提供了selenium库来实现Selenium的操作,selenium库不是Python的内置的标准库,使用之前需要安装。
访问:http://npm.taobao.org/mirrors/chromedriver/ 下载对应的ChromeDriver版本。解压下载好的安装包,将chromedriver.exe复制到anaconda3安装目录的Scripts文件夹下。然后在Anaconda3的环境下输入chromedriver验证ChromeDriver环境变量是否配置成功。
(base) C:\Users\Bing>chromedriver Starting ChromeDriver 94.0.4606.61 (418b78f5838ed0b1c69bb4e51ea0252171854915-refs/branch-heads/4606@{#1204}) on port 9515 Only local connections are allowed. Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe. ChromeDriver was started successfully.
1.2,Selenium库的使用
声明浏览器对象:selenium库支持多种浏览器。例如,Google Chrome、Firefox、Edge等网页浏览器,Adnroid、BlackBerry等手机端的浏览器以及PhantomJS无界面浏览器等。
from selenium import webdriver brower = webdriver.Chrome() brower = webdriver.Firefox() brower = webdriver.Edge() brower = webdriver.PhantomJS()
访问网页:使用get()方法请求网页(传入URL参数即可),会弹出浏览器窗口并自动访问网页,然后可以调用浏览器对象的属性和方法获取网页的信息(如HTML源代码)。
属性或方法 说明 page_source 获取当前页面HTML代码 current_url 获取当前页面URL title 获取当前页面源代码中title标签的文本信息 get_cookies() 获取所有cookie get_cookie(name) 获取指定cookie add_cookie({}) 添加cookie,参数为字典类型 delete_all_cookies() 删除所有cookie delete_cookie(name) 删除指定cookie 定位节点:selenium库提供了一系列定位节点的方法。
方法 说明 find_element_by_class_name() 通过节点的class属性值定位 find_element_by_name() 通过节点的name属性名定位 find_element_by_id() 通过节点的id属性值定位 find_element_by_link_text() 通过超链接节点的文本定位 find_element_by_partial_link_text() 通过超链接节点包含的部分文本定位 find_element_by_tag_name() 通过节点名定位 find_element_by_xpath() 使用XPath语法定位 find_element_by_css_selector() 使用CSS选择器定位 上表中的方法匹配的是第一个符合条件的节点,如果把方法名中的element改为elements,匹配的将是所有符合条件的节点,返回一个列表。调用方法定位到节点后会返回一个WebElement类型的对象,该对象提供了一些方法来提取所需的信息。
方法 说明 get_attribute() 获取属性 text 获取文本 tag_name 获取标签名 id 获取节点id from selenium import webdriver # 初始化Google Chrome浏览器对象,并赋值给browser brower = webdriver.Chrome() # 请求淘宝首页,打开一个浏览器窗口 brower.get('http://www.taobao.com/') # 输出id属性值为q的结点 print(brower.find_element_by_id('q')) # 输出class属性值为btn-search定位的结点 print(brower.find_element_by_class_name('btn-search')) # 输出使用Xpath定位id属性值为q的节点 print(brower.find_element_by_xpath('//input[@id="q"]')) # 输出使用CSS选择定位器定位的class属性值为"btn-search"的姐节点 print(brower.find_element_by_css_selector('.btn-search')) # 定位class属性为btn-search的节点 element = brower.find_element_by_class_name('btn-search') # 输出element的type属性值 print(element.get_attribute("type")) # 输出element的文本 print(element.text) # 输出element的节点名 print(element.tag_name) # 输出element的id print(element.id) ================================= <selenium.webdriver.remote.webelement.WebElement (session="dd326e57ec62be9c2a1d8394ca078158", element="09e934ae-4b5b-4815-b241-76b8421328ba")> <selenium.webdriver.remote.webelement.WebElement (session="dd326e57ec62be9c2a1d8394ca078158", element="39b010c4-cb6a-4d36-a437-e33d97e93323")> <selenium.webdriver.remote.webelement.WebElement (session="dd326e57ec62be9c2a1d8394ca078158", element="09e934ae-4b5b-4815-b241-76b8421328ba")> <selenium.webdriver.remote.webelement.WebElement (session="dd326e57ec62be9c2a1d8394ca078158", element="39b010c4-cb6a-4d36-a437-e33d97e93323")> submit 搜索 button 39b010c4-cb6a-4d36-a437-e33d97e93323
模拟浏览器操作:selenium库提供了模拟浏览器执行一些操作的方法。
对象 方法 说明 节点 send_key(string) 输入文字,参数类型为字符串 clear() 清除文字 click() 单击节点 浏览器 maximize_window() 最大化浏览器窗口 minize_window() 最小化浏览器窗口 forward() 页面前进 back() 页面后退 refresh() 页面刷新 switch_to 切换窗口或嵌套页面 close()/quit() 关闭浏览器 在实际Web测试中,会有很多鼠标的操作,不单单只有单击,有时候还要用到右击、双击、拖动等操作。selenium库中的ActionChains类提供了实现这些操作的方法。
方法 说明 方法 说明 click(element) 单击鼠标左键 content_click(element) 单击鼠标右键 double_click(element) 双击鼠标左键 drag_and_drop(element) 拖动鼠标到某个节点后松开 move_to_element(element) 鼠标移动到某个节点 click_and_hold(element) 鼠标左键按住某个节点,不松开 key_down(value,element) 按下特殊键,只能用Ctrl、Alt或Shift键 key_up(value, element) 松开特殊键 move_by_offset(xoffset, yoffset) 鼠标从当前位置按偏移移动 move_to_element_with_offset
(element,xoffset,yoffset)
鼠标移动到某个节点并偏移 perform() 执行操作产生的行动 release(element) 在某个节点位置松开鼠标左键 #打开淘宝聚划算 import time from selenium import webdriver # 初始化Google Chrome浏览器对象,并赋值给browser brower = webdriver.Chrome() brower.maximize_window() # 请求淘宝首页,打开一个浏览器窗口 brower.get('http://www.taobao.com/') time.sleep(2) element = brower.find_element_by_xpath('/html/body/div[3]/div/ul[1]/li[2]/a') element.click() brower.maximize_window()
页面等待:很多网页采用了Ajax技术,程序无法确定某个节点是否已经完成加载。如果页面实际加载的时间过长,会导致程序使用未加载出来的节点,此时就会抛出NullPoint异常。为了避免这种情况,selenium库提供了显式等待和隐式等待两种等待方式。
(1)selenimu库提供了WebDriverWait类实现显式等待,WebDriverWait的语法格式:
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) driver:浏览器对象 -timeout:等待时间 -poll_frequency:检查频率,程序每隔这个时间检查一次,如果满足则执行下一步,如果不满足则继续等待,默认0.5s -ignored_exceptions:表示超时后的异常信息
WebDriverWait类须与unit()方法或until_not()方法结合使用。例如,WebDriverWait(driver,10).until(method, message=""),表示在10s内,每隔0.5s,调用until里的方法,直到它满足了预期条件,如果时间超过10s,则抛出异常。
selenium库的expected_conditions类提供了until()方法和until_not()方法中预期条件判断的方法。
- title_is():标题是内容。
- title_contains():标题包含某内容。
- presence_of_element_located():节点加载完成,传入定位元组,如(BY.ID,'p')。
- presence_of_all_elements_located():所有节点加载完成。
- visibility_of_element_located():节点可见,传入定位元组。
- visibility_of():可见,传入节点对象。
- text_to_be_present_in_element():某个节点文本包含某文字。
- text_to_be_present_in_element_value():某个节点值包含某文字。
- frame_to_be_available_and_switch_to_it():加载并切换。
- invisibility_of_element_located():节点不可见。
- element_to_be_clicked():节点可单击。
- staleness_of():判断节点是否仍存在DOM中,常用于判断页面是否已刷新。
- element_to_be_clicked():节点可单击。
- element_to_be_selected():节点可选择,传入节点对象。
- element_located_to_be_selected():节点可选择,传入定位元组。
- element_selection_state_to_be():传入节点对象和状态,相等则返回True,否则返回False。
- element_located_selection_state_to_be():传入定位元组和状态,相等则返回True,否则返回False。
- alter_is_present():是否出现警告。
(2)selenium库直接使用implicityly_wait(timeout)方法实现隐式等待。该方法表示在规定时间内页面的所有元素都加载完了就执行下一步,否则一直等待时间截止,然后再继续下一步。
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC browser = webdriver.Chrome() browser.maximize_window() browser.get('https://www.taobao.com/') element = WebDriverWait(browser, 1).until( EC.presence_of_all_elements_located((By.XPATH, '/html/body/div[3]/div/ul[1]/li[2]/a') ) ) print(element[0].text) ====================== 聚划算
1.3,爬取淘宝聚划算商品信息
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC browser = webdriver.Chrome() browser.maximize_window() wait = WebDriverWait(browser,5) browser.get('https://www.taobao.com/') time.sleep(2) #下拉倒底部,加载商品内容 browser.execute_script("window.scrollTo(0,document.body.scrollHeight)") time.sleep(2) titles = browser.find_elements_by_xpath('/html/body/div[7]/div/div/div[1]/div/a[1]/h4') for title in titles: print(title.text) ======================================= 景德镇陶瓷56头新中式骨瓷餐具套装日式碗碟盘筷家用结婚乔迁礼品 桌面抽屉式收纳盒柜子化妆品首饰多层箱学生小号迷你储物整理办公 家用沥水篮不锈钢工艺水果篮蔬菜篮l漏水洗菜篮子圆形厨房加厚清 藤编脏衣篮大号带盖脏衣篓编织筐家用放衣娄装玩具框脏衣服收纳筐 陶瓷酒壶花雕酒壶老式酒壶中式酒壶3钱高脚酒杯瓷酒壶套装小/大号 zakka木碟 全实木小杯 酒店小吃碟 KTV干果碟餐具小盘子 零食小碗 陶瓷碗带盖饭盒大号微波炉骨瓷保鲜碗日式泡面碗学生大盖碗四件套 ......
1.4,爬取知网文章信息
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from lxml import etree browser = webdriver.Chrome() wait = WebDriverWait(browser,5) def searcher(keyword): browser.get('https://www.cnki.net/') browser.maximize_window() time.sleep(3) input = wait.until(EC.presence_of_element_located((By.CLASS_NAME,'search-input'))) input.send_keys(keyword) wait.until(EC.presence_of_element_located((By.CLASS_NAME,'search-btn'))).click() time.sleep(3) wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="perPageDiv"]/div/i'))).click() wait.until(EC.presence_of_all_elements_located((By.XPATH,'//*[@id="perPageDiv"]/ul/li[3]')))[0].click() time.sleep(3) parse_page() def parse_page(): html = browser.page_source selector = etree.HTML(html) dates = selector.xpath('//table[@class="result-table-list"]/tbody/tr') for date in dates: name = str(date.xpath('td[@class="name"]/a/text()')).replace("\\n","").replace(" ","") author = date.xpath('td[@class="author"]/a/text()') source = date.xpath('td[@class="source"]/a/text()') time = str(date.xpath('td[@class="date"]/text()')).replace("\\n","").replace(" ","") data = str(date.xpath('td[@class="data"]/text()')).replace("\\n","").replace(" ","") print(name,author,source,time,data) if __name__ == '__main__': searcher("Python") ============================================== ['湖南省财政收入影响因素分析及预测——基于','软件实现'] ['秦权'] ['中国市场'] ['2021-10-15'] ['期刊'] ['多维数组库Xarray在数据处理中的应用'] ['曹永正', '王立鹏', '高山', '温连杰', '王翠'] ['科学技术创新'] ['2021-10-15'] ['期刊'] ['基于STM32的多通道温度测量系统研究与设计'] ['侯志伟', '包理群', '杜青青'] ['工业仪表与自动化装置'] ['2021-10-14'] ['期刊'] ['基于Isight和','的民机客舱立柱结构优化设计'] ['方阳', '张卫文', '张洋洋'] ['机械强度'] ['2021-10-12'] ['期刊'] ['利用','实现对存储在Mysql数据库的日志文件的分析和保存'] ['李晓雨'] ['科学技术创新'] ['2021-10-12'] ['期刊']
2,模拟登录&验证码
2.1,模拟登录
使用Cookie保持登录状态的方法,但是这种方法需要在浏览器中输入用户名和密码登录后,再复制用户状态下网页请求头中的Cookie,将其设置到程序中。除了使用Cookie,爬虫程序还可以使用Session保持登录。Session也是一种记录客户端的状态的会话机制,它保持在服务器上。
Session会话机制的过程:当用户通过浏览器登录网站时,会在服务器端生成一个Session,同时会为该Session生成唯一的SessionID,然后通过响应将SessionID返回给浏览器;当再次访问网站时,浏览器会将Session ID放到请求头中一起发送给服务器,服务器从请求中提取SessionID,并和保存的所有Session ID进行对比,查找相应的Session,从而实现保持登录。
requests库中的session对象可以模拟并自动更新Cookie,实现并保持登录,常用方法和属性如下:
- session():创建一个session对象。
- headers:session对象的请求头。
- cookies:session对象的Cookie。
- update():设置修改session对象的属性,如session.cookies.update({'id':'sessionID'}),如果cookies属性中的id属性不存在,则设置该信息;如果存在则修改该信息为sessionID。
import requests from bs4 import BeautifulSoup url = "https://library.nudt.edu.cn/sso/login" dataValue = { 'account': '********', 'password': '*********', 'wfwfid': '182' } headersValue = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4651.0 Safari/537.36', 'X-Requested-With': 'XMLHttpRequest' } cookie = 'historyRefer=https%3A%2F%2Flibrary.nudt.edu.cn%2F' cookies = {} # 将cookie转换为字典 for line in cookie.split(";"): key, value = line.split('=', 1) cookies[key] = value s = requests.session() s.headers = headersValue s.cookies.update(cookies) r = s.post(url, data=dataValue, headers=headersValue) print(r.text)
2.2,图片验证码
识别思路:识别图片验证码常使用图像识别技术。这种技术称为光学字符识别(OCR),它通过检测暗、亮的模式确定其形状,然后使用字符识别方法将形状翻译成计算机文字。而在识别过程中,一些图片存在多余线条的干扰,需要对图片进行灰度和二值化处理,以提高图片的识别率。
- 获取验证码图片。在网页的HTML源代码中查找验证码节点,获取链接属性,然后发送请求,获取验证码图片。
- 将图像转化为灰度图像。
- 将灰度图像转换为二值图像。指定二值化的阀值,将像素小于阀值的地方设置成黑色,将像素大于阀值的地方设置成白色,取出图片中的线条。
- 使用OCR技术识别图中的字母或数字。
安装Tesseract-OCR:pytesseract库是Python的一个OCR识别库,但其实是对Tesseract做了一层Python API封装。因此,在安装pytesseract库之前,需要先安装Tesseract-OCR(tesseract-ocr-w64-setup-v5.0.0.20190623.exe ),然后配置环境变量。下载地址
安装pytesseract库:pytesseract库不是Python内置标准库,使用之前需要安装。
识别验证码:image_to_string()方法是pytesseract库提供的识别图片中文本的方法,它将图片上的字母或数字转为字符串。该方法的参数是Image对象,它可以由PIL库中的Image模块生成。Image模块还提供了图形基本操作的方法。
- open():打开图片,返回一个Image对象。
- convert(mode):不同模式图像之间的转换,mode为L,表示灰度图形;mode为1,表示二值图像。
- point(table, '1'):点方法,将灰度图形转换成二值图形,table为根据指定二值化阀值生成的像素表。
- show():显示图片。
- save():保存图片。
OCR识别图片验证码时,有时识别不准确,实际应用需要尝试多次,直到识别正确为止。
import pytesseract import requests from PIL import Image from io import BytesIO from bs4 import BeautifulSoup import re headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4662.6 Safari/537.36' } def login(): url = "http://www.daimg.com/member/index.php" s = requests.session() s.headers = headers r = s.get(url) soup = BeautifulSoup(r.text, 'lxml') captcha = soup.select('#vdimgck')[0]['src'] captcha_url = 'http://www.daimg.com' + str(captcha[2:]) print(captcha_url) r = s.get(captcha_url) try: image = Image.open(BytesIO(r.content)) # image.show() code = pytesseract.image_to_string(image) print("识别原图的验证码字符串:", code) image = image.convert('L') # image.show() code = pytesseract.image_to_string(image) print("识别灰度图的验证码字符串:", code) table = [] threshold = 127 # 二进制阀值 for j in range(256): if j < threshold: table.append(0) # 填黑色 else: table.append(1) # 填白色 # 对像素操作 image = image.point(table, '1') image.show() code = pytesseract.image_to_string(image) url = "http://www.daimg.com/member/index_do.php" params = { 'fmdo': 'login', 'dopost': 'login', 'gourl': '', 'userid': '****************', 'pwd': '***************', 'vdcode': code.strip() } res = s.post(url, data=params, headers=headers) contents = re.findall('<h2>(.*?)</h2>', res.text, re.S)[0] print(contents) # if str(contents).find("验证码错误!") >= 0: # login() # else: # print(contents) except Exception as e: print(e) if __name__ == '__main__': login() ======================================= http://www.daimg.com/include/vdimgck.php 识别原图的验证码字符串: OYLI 识别灰度图的验证码字符串: OYLI 成功登录,5秒钟后转向系统主页...
2.3,点触验证码
点触验证码是给出一张复杂的图片,根据图片上的指示进行点击即可完成验证。例如,哔哩哔哩登录页面的点触验证码。这种情况下需要获取点击的位置坐标,此时,可通过第三方收费的接口来实现。
注册超级鹰账号,下载Python语言Demo:链接
import requests from selenium import webdriver import time from io import BytesIO from selenium.webdriver import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from PIL import Image import Chaojiying browser = webdriver.Chrome() wait = WebDriverWait(browser, 5) browser.maximize_window() browser.get("https://passport.bilibili.com/login?from_spm_id=333.851.top_bar.login") time.sleep(2) input = wait.until(EC.presence_of_element_located((By.ID, 'login-username'))) input.send_keys("**********") input = wait.until(EC.presence_of_element_located((By.ID, 'login-passwd'))) input.send_keys("**********") wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="geetest-wrap"]/div/div[5]/a[1]'))).click() time.sleep(2) pick_img_label = browser.find_elements_by_xpath('//img[@class="geetest_item_img"]')[0] src = pick_img_label.get_attribute('src') # 获取点触图片链接 img_content = requests.get(src).content # 获取图片二进制内容 f = BytesIO() f.write(img_content) img0 = Image.open(f) # 将图片以文件的形式打开,主要是为了获取图片的大小 scale = [pick_img_label.size['width'] / img0.size[0], pick_img_label.size['height'] / img0.size[1]] # 获取图片与浏览器该标签大小的比例 result = Chaojiying.Chaojiying_Client('**********', '**********', ' 923629') result = result.PostPic(img_content, 9004) print(result["pic_str"]) position = result['pic_str'].split('|') # position = ['110,234','145,247','25,185'] position = [[int(j) for j in i.split(',')] for i in position] # position = [[110,234],[145,247],[25,185]] for items in position: # 模拟点击 ActionChains(browser).move_to_element_with_offset(pick_img_label, items[0] * scale[0], items[1] * scale[1]+20).click().perform() #修正偏差 time.sleep(1) wait.until(EC.presence_of_element_located((By.XPATH, '//a[@class="geetest_commit"]'))).click()
2.4,滑动拼图验证码
滑动拼图验证码需要拖动滑块拼合图像,若图像完全拼合,则验证成功,否则需要重新验证。滑动拼图验证码一般的解决方法是:获取滑块移动至缺口的距离,生成滑动轨迹,然后拖动滑块到缺口处,实现滑动拼图验证。
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains import time from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from PIL import Image import os import sys path = os.path.dirname(os.path.dirname(__file__)) sys.path.append(path) import Chaojiying import requests from hashlib import md5 class main(): def __init__(self): self.url = 'https://i.qq.com/' self.file_path = './code_picture.png' self.file_path2 = './code_picture2.png' self.distance = 0 self.key = 0 # 启动浏览器 def Launch_browser(self): self.driver = webdriver.Chrome() self.wait = WebDriverWait(self.driver, 10, 0.5) self.driver.maximize_window() self.driver.get(self.url) time.sleep(5) self.driver.switch_to.frame('login_frame') self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="bottom_qlogin"]'))).click() time.sleep(2) input = self.wait.until(EC.presence_of_element_located((By.ID, 'u'))) input.send_keys("1966799809") input = self.wait.until(EC.presence_of_element_located((By.ID, 'p'))) input.send_keys("shao2956008*") time.sleep(2) self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'login_button'))).click() time.sleep(2) # 截图 def get_picture(self): self.driver.save_screenshot(self.file_path) # 分割截图获取验证码图片 def crop_picture(self): image = Image.open(self.file_path) weight, height = image.size # 这里的比例需要自己摸索,实际上只需要横坐标准确即可 box = (weight * 1/2, height * 1/2 - 230, weight * 1/2 + 450, height * 1/2 + 30) region = image.crop(box) region.save(self.file_path2) # 超级鹰 def cjy(self): # 用户中心>>软件ID 生成一个替换 923629 self.chaojiying = Chaojiying.Chaojiying_Client('shao12138', 'shao12138', ' 923629') # chaojiying = Chaojiying_Client('超级鹰用户名', '超级鹰密码', '910001') # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要// im = open('./code_picture2.png', 'rb').read() # 9101 验证码类型 官方网站>>价格体系 3.4+版 print 后要加() # 咨询了一下滑动验证码是选择9101 re = self.chaojiying.PostPic(im, 9101) print(re) # print(re['pic_str']) # 减去一半滑块长度 self.distance = int(re['pic_str'].split(',')[0]) - 25 print(self.distance) self.im_id = re['pic_id'] print(self.im_id) # 获取轨迹 def get_track(self): # 轨迹 self.track = [] # 设置一个分隔线,之前为匀加速运动,之后为匀减速运动 mid = self.distance * 4 / 5 # 用于记录当前的移动距离 current = 0 # 时间间隔 t = 0.2 # 初速度 v = 0 while current < self.distance: if current < mid: a = 8 else: a = -12 v0 = v v = v0 + a * t move = v * t + 1 / 2 * a * t * t current += move self.track.append(round(move)) for i in self.track: print(str(i),",") # 模拟移动 def move(self): # 直接移动到指定坐标 self.track = [self.distance+50] frame = self.driver.find_element_by_id("tcaptcha_iframe") self.driver.switch_to.frame(frame) time.sleep(2) self.slider = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'tc-drag-thumb'))) # 点击和按住 ActionChains(self.driver).click_and_hold(self.slider).perform() time.sleep(2) # 拖动 for x in self.track: ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=0).perform() time.sleep(1) time.sleep(2) # 松开鼠标 ActionChains(self.driver).release().perform() # 检测结果(目前不做检测,先白嫖一下) def check(self): if self.key ==1: pass # 出错时反馈给超级鹰,取消扣分 else: re = self.chaojiying.ReportError(self.im_id) print(re) # main方法 def main(self): self.Launch_browser() self.get_picture() self.crop_picture() self.cjy() # 目前选择直接跳到缺口 #self.get_track() self.move() self.check() if __name__ == '__main__': ma = main() ma.main()
3,爬取APP和PC客户端数据
3.1,配置Fiddler
Fiddler是常用的APP抓包工具。它是位于客户端和服务端的HTTP代理,能够记录客户端和服务器端之间所有HTTP请求,可以针对特定HTTP请求分析请求数据、设置断点、调试Web应用、修改请求数据,甚至可以修改服务器端返回的数据,功能非常强大。使用Fiddler爬取APP数据的步骤如下:
(1)下载和安装Fiddler4。
(2)设置Fiddler和Android手机。
- 打开Fiddler,在菜单栏选择Tools → Option选项。
- 打开Option对话框,切换到HTTPS选项卡,勾选Decrypt HTTPS traffic 复选框(表示可以记录HTTPS请求),在展开的列表中勾选Ignore server certificate error复选框。
- 切换到Connections选项卡中,勾选Allow remote computers to connect复选框(允许别的远程设备发送HTTP/HTTPS请求到Fiddler),单击OK。
- 重启Fiddler
(3)设置Android手机
- 确保Android手机和计算机在同一局域网内。确保Fiddler完成设置,并正在运行。
- 打开CMD,输入ipconfig命令,查看无线局域网适配器WLAN的IPV4地址。
- 在手机端选择设置→无线和网络→WLAN选项,长按已连接的网络,在弹出的列表中选择修改网络选项。
- 打开选择代理类型界面,勾选显示高级选项复选框,在弹出的列表中选择代理选项,然后在弹出的界面中勾选手动单选框。
- 打开设置代理界面,设置服务器主机名为10.129.197.92的无线局域网适配器,设置服务器端口号为8888,点击保存按钮。
- 在Android中使用自带的浏览器访问http://10.129.197.92:8888,然后点击FiddlerRoot certificate链接下载证书。
- 进入手机的下载管理界面,点击下载好的FiddlerRoot.cer文件,输入锁屏密码,设置证书名称为FiddlerRoot certificate,点击确定按钮,安装证书。
- 安装完成后,即可完成Android手机的设置。
3.2,爬取酷我音乐APP信息
爬取每日推荐音乐列表
import json import pytesseract import requests from PIL import Image from io import BytesIO from bs4 import BeautifulSoup import re headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4662.6 Safari/537.36' } url = "http://mobi.kuwo.cn/mobiweb.s?prod=kwplayer_ar_9.5.0.2&f=web&num=40¬race=0&source=kwplayer_ar_9.5.0.2_hwtest.apk&type=rcm_discover&kweexVersion=1.1.3&apiv=3&uid=630583330&tab=1&loginUid=514122657&vip_member=0" r = requests.get(url) json_data = json.loads(r.text) for i in json_data['child'][0]['child']: print(i['title'])
3.3,配置Proxifier
Fiddler不仅可以抓取APP的数据包,还可以借助Proxifier抓取PC客户端的数据包。由于一般的C/S客户端不能设置代理,所以直接使用Fiddler抓取不到数据,此时,需要使用Proxifier抓取PC客户端的请求并发送给Fiddler,然后使用Fiddler来分析请求和响应。
(1)下载和安装Fiddler4。
(2)设置Fiddler,打开Option对话框,切换到HTTPS选项卡,勾选Decrypt HTTPS traffic 复选框(表示可以记录HTTPS请求),在展开的列表中勾选Ignore server certificate error复选框,并勾选Check fo certificate revocation复选框。
(3)设置Proxifier
- 启动Proxifier,在菜单栏中选择配置文件→代理服务器选项。
- 打开代理服务器对话框,单击添加按钮。
- 在打开的对话框中设置地址为127.0.0.1,设置端口为8888,勾选HTTPS单选钮。
- 在菜单栏选择配置文件→代理规则选项。
- 打开代理规则对话框,单击添加按钮。
- 在打开的对话框中的应用程序编辑框中输入Fiddler.exe,在动作的下拉列表中选择Direct选项,单击确认按钮。
3.4,爬取酷我音乐PC客户端数据
搜索凤凰传奇的歌曲
import requests import json headers = { 'Host': 'dhjss.kuwo.cn', 'Connection': 'keep-alive', 'Accept': 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4', 'Cookie': 'ad_dist=%BA%FE%C4%CF' } url = "http://dhjss.kuwo.cn/s.c?all=%E5%87%A4%E5%87%B0%E4%BC%A0%E5%A5%87&rformat=json&tset=artist,album,playlist,subject,ranklist&version=MUSIC_9.1.1.5_PT&resenc=utf8" res = requests.get(url,headers=headers) json_data = json.loads(res.text) for data in json_data['newsong']: print(data['name']) ========================================= 万象长安(《剑网3》十二周年纪念主题曲) 好运来(《梦幻西游网页版》周年庆主题曲) 普通Disco(逆水寒新春贺岁曲) 郎的诱惑
4,其他案例
4.1,爬取大众点评数据
import csv import json import time from multiprocessing import Pool import requests import urllib3 from lxml import etree urllib3.disable_warnings() headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.44', 'Accept-Encoding': 'gzip, deflate, br', 'Cookie': 'fspop=test; _lxsdk_cuid=17d029e3670c8-0bc1e17a6af2a2-561a1053-1fa400-17d029e3670c8; _lxsdk=17d029e3670c8-0bc1e17a6af2a2-561a1053-1fa400-17d029e3670c8; _hc.v=ef0f1901-6319-c540-7af9-c74b8375767c.1636426464; cy=1; cye=shanghai; s_ViewType=10; _dp.ac.v=2dca509e-fe8e-44a9-bd25-c22d4525614e; Hm_lvt_602b80cf8079ae6591966cc70a3940e7=1636426464,1636428262; ctu=082f1fe628b8e1032a256c6a33e27b658e29c0cf2cd8ce1d2513f29bc417d9d8; dplet=849884c9ab4d5f707d158dad1a666ec9; dper=c39d8a1af93555128b0bd851f2239ffeb88869a90964cc25fefca20762371a218e04e14700064a137f91d923333560474fcf6c94b75dc287345b219ef4dc0df298f7e445a2f8c2485e7953671f804bf9ca100e4148cfa0ab8f052d202ba8ba2d; ll=7fd06e815b796be3df069dec7836c3df; ua=18274961715; Hm_lpvt_602b80cf8079ae6591966cc70a3940e7=1636436315; _lxsdk_s=17d03221390-345-c08-f38%7C%7C451' } # 保存到Excel中 f = open("douban.csv", "a", newline="") writer = csv.writer(f) #writer.writerow(("id", "name", "evaluate_number", "price", "address")) writer = csv.writer(f) urls = ['http://www.dianping.com/search/keyword/1/0_%E5%92%96%E5%95%A1/p{}'.format(str(i)) for i in range(50, 51)] for url in urls: res = requests.get(url, headers=headers) selector = etree.HTML(res.text) page_shopes = selector.xpath('//div[@id="shop-all-list"]/ul/li') for shop in page_shopes: #ID shope_id = shop.xpath('div[2]/div[1]/a/@data-shopid') shop_address_url = shop.xpath('div[2]/div[1]/a/@href') shope_name = shop.xpath('div[2]/div[1]/a/h4/text()') # 评分 shope_score_temp = shop.xpath('div[2]/div[2]/div[1]/div/span[1]/@class') shope_score = str(shope_score_temp)[12:13] + "." + str(shope_score_temp)[13:14] time.sleep(1) # 评论数-API shop_evaluate_url ="http://www.dianping.com/ajax/json/shopDynamic/allReview?shopId={}&cityId=1&shopType=10&tcv=mn7fl73gmx&_token=eJxNj1FvgjAUhf9LX9dASwuzJD4QYZuAY7Og2YwPCAxRQYQGxGX%2FfSWZyZKbnHO%2Fe09y7zdo5ikwMUKIYgi6rAEmwApSDACBaOXEIAYlBsGM6RMIkv9MQzrTIdg1KxuYG6wRApnBtiNZSrDBTEMQownawrun0mtU1rg1l0tgL0Rtqmrf90paxFVdVLmSnEu13Z9r9Sm29k715rGoe4lPCZdHAZkswzGJMdUgQyM4jkBq%2FKfi3i%2FkOzLUFnklXeZeQ97S9vK1XLThKhoG5nGuDX6CfR4R%2F%2BaI14h3wTCbWLzJT0EZUz1f0TWN1xkPS9fK7Gu0uMywK%2Bx3EhVHcUuuge91iCc4WKbux%2FHEqlKvy0r%2FzHf1Q7r2LMd6fM4Ph346BT%2B%2FlqNpsw%3D%3D&uuid=ef0f1901-6319-c540-7af9-c74b8375767c.1636426464&platform=1&partner=150&optimusCode=10&originUrl=http%3A%2F%2Fwww.dianping.com%2Fshop%2FFaAhEnPK9UvHalcS".format(str(shope_id[0])) res = requests.get(shop_evaluate_url, headers=headers) json_data = json.loads(res.text) #报错后重新登陆,更新cookie和shop_evaluate_url ,将其中的shopId换成{},换下一页或者统计新的页数=条数/25 shop_evaluate_number = json_data.get("reviewCountGood") # 人均价格 shop_price_all = json_data.get("reviewAllDOList") shop_price_sum = 0 shop_price_count = 0 for shop_price_all_one in shop_price_all: shop_price = shop_price_all_one.get("reviewDataVO").get("reviewData").get("avgPrice") if shop_price != "": shop_price_count += 1 shop_price_sum += int(shop_price) if shop_price_count==0: shop_price = 0 else: shop_price = shop_price_sum / shop_price_count time.sleep(1) shop_address_url = "http://www.dianping.com/shop/" + str(shope_id[0]) res = requests.get(shop_address_url, headers=headers) selector = etree.HTML(res.text) shope_details = selector.xpath('//div[@class="breadcrumb"]/a/text()')[2:] shope_detail = "" for i in range(len(shope_details)): if i != len(shope_details) - 1: shope_detail += str(shope_details[i]).strip() + "-" else: shope_detail += str(shope_details[i]).strip() # 保存到Excel中 print(shope_id[0], shope_name[0], shop_evaluate_number, shop_price, shope_detail) writer.writerow((shope_id[0], shope_name[0], shop_evaluate_number, shop_price, shope_detail))