一、引入
- 爬虫和反爬虫的斗争
- selenium最初本来是用来测试网站的,但是爬虫人员将其引过来可以解决动态网页的问题
静态网页与ajax动态加载
- 以前爬取的网页都是静态的网页
- 何为静态网页,其实就是我们向一个网站发起请求得到响应,那么这些响应的数据都是网页的源代码中,通过response就可以得到数据
- 除了静态网页,还有一些网站数数据不在这个请求得到url地址当中,那么这些护具有可能是通过ajax技术加载出来的数据,例如12306的班次的信息不在url中,查询的内容只是对网页的部分内容更新,这个就是ajax动态加载出来的
- element是最终的显示结果,会经过渲染和多次请求,只能作为参考,只有源代码才是准确的,如果观察element的数据在网页源代码中没有,那就可能藏着其他文件里,动态加载出来的
ajax动态加载的数据怎么处理
- 网页有我们要爬取的数据,但是网页的源码中没有,该如何解决
- 1.分析真正的ajax真正的数据接口,找到接口的url。从而来获取数据
- 2.通过selenium来模拟浏览器获取数据
ajax基本介绍
- 动态了解HTML技术
- JS
• 是网络上最常用的脚本语言,它可以收集用户的跟踪数据,不需要重载页面直接提交表单,在页面嵌入多媒体文件,甚至运行网页
- jQuery
• jQuery是一个快速、简介的JavaScript框架,封装了JavaScript常用的功能代码
- ajax
• ajax可以使用网页实现异步更新,可以在不重新加载整个网页的情况下,对网页的某部分进行更新
二、配置Selenium、chromdriver
Selenium 介绍
- selenium是一个web的自动化测试工具,最初是为网站自动化测试而开发的,selenium可以直接运行在浏览器上,它支持所有主流的浏览器,可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏
- 安装Selenium:pip install selenium, 安装教程
- 要使用Selenium,还要下载浏览器驱动,第一次启用驱动要指定地址,或者将其安装在当前工作目录下
chromedriver
- chromedriver是一个驱动Chrome浏览器的驱动程序,使用他才可以驱动浏览器。当然针对不同的浏览器有不同的driver。以下列出了不同浏览器及其对应的driver:
- chromedriver 地址 http://chromedriver.storage.googleapis.com/index.html 选择和浏览器版本匹配的驱动器
-
firefoxdriver类似,火狐浏览器的驱动器
Phantomjs
- 无头浏览器,不会打开页面,它是没有和用户交互界面的,一个完整的浏览器内核,包括js解析引擎,渲染引擎,请求处理等,但是不包括显示和用户交互页面的浏览器
- 用途:
- 1 有的程序是用的是它
- 2 对比的去学习chromedriver
- 区别:
- Phantomjs可以通过截屏driver.save_screenshot(‘baidu.png’)来获取测试结果,不会和 chromedriver一样弹出浏览器窗口,动态看操作步骤。
- Phantomjs对于Selenium是过时的程序,所以会报错警告
三、Selenium的基本操作
- from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
- 当属性有空格的时候,定位的时候可能会找不到该元素,例如account-tab-account on 如何解决呢?
- 1.可以选其中的一部分(通过测试)先选择长一点的尝试,去掉on
- 2 xpath来定位
- 注意:没有网的话用 selenium会报错
(一)设置驱动、退出驱动
driver = webdriver.Chrome(路径)
- 路径:填的是chromedriver.exe的路径,如果当前工作文件夹有,可以不填
- Chrome:这个是打开的是Chrome浏览器,也可以选择火狐webdriver.firefox()或无头浏览器webdriver.PhantomJS()
设置无界面模式
- 设置了这个后就不会再弹出浏览器窗口了,可以截屏,但和不同无头浏览器不完全一样,无头浏览器截屏可以看到它是没有浏览器的,不会有拖动框。
# 创建chrome设置对象
options = webdriver.ChromeOptions()
# 设置无界面功能 --headless 浏览器无界面 --xxxx
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.quit()
(二)网页打开、关闭等基本操作
1.打开网页、多个网页、切换窗口
打开网页
- get(url)接连打开两个网页,后面会直接覆盖前面的
如何打开多个窗口呢?
- driver.execute_script(‘window.open(“https://www.douban.com/”)’)
- 但是当前工作环境,后面操作对象仍然是前面的窗口,要想在新的窗口进行操作的换,还需要主动的切换窗口
- 有时候窗口中有很多子tab页面。这时候肯定是需要进行切换的。selenium提供了一个叫做switch_to_window来进行切换,具体切换到哪个页面,可以从driver.window_handles中找到
切换窗口
- driver.switch_to.window(driver.window_handles[1]) 序号就是代指了网页的顺序索引,从0开始
显示当前窗口
- driver.current_url
2.关闭当前窗口
driver.close()
- 关闭当前窗口,只会关闭一个,当前如果有多个窗口的话,只会关闭当前工作的窗口
- 因为关闭的是当前工作的窗口,所以后面再继续操作都会报错,即使打开另一个窗口的操作也不行,这个时候就必须要切换还在的窗口,然后再进行下一个步骤
3.网页全屏与截屏
全屏
网页截屏
- driver.save_screenshot(‘图片名.png’)`
- 截取的是当前工作的网页
(三)定位元素
方法
- element匹配第一个
elements 匹配所有,返回列表
- driver.find_element(By.某,对应某值)
driver.find_elements(By.某,对应某值)
- driver.find_element_by_ 某(对应某值)
driver.find_elements_by_ 某(对应某值)
1.通过标签
- driver.find_element_by_tag_name(‘标签名’)
driver.find_elements_by_tag_name(‘标签名’)
- 不够精确,不常用
2.通过属性值
- id
- driver.find_element_by_id(‘属性值’) 方法指定属性
driver.find_elements_by_id(‘属性值’)
- driver.find_element(By.ID,‘属性值’) 括号指定属性
driver.find_element(By.ID,‘属性值’)
- class(by_class_name用的是class_name)、name、link等属性同理
3.通过xpath
- driver.find_element_by_xpath(xpath路径)
- 可以直接复制某行的xpath的路径
(四)标签元素处理
1.获取文本text
2.获取属性值get_attribute('属性')
3.获取文本输入框内容get_attribute('value')
- InputTag.get_attribute(‘value’)
(五)操作元素
1.输入框-----传值send_key()与清空值clear()
send_key()传值
- 第一步:找到这个元素input_tag,定位到的输入框标签位置。
第二步:使用send_keys(value),将数据填充进去
input_tag.send_keys(‘要传的值’)
clear()清空值
2.按钮-----click()点击
- 操作按钮有很多种方式。比如单击、右击、双击等。这里讲一个最常用的。就是点击
click()点击
- 第一步:找到这个元素button,定位到的按钮标签位置。
第二步:使用.click()
button.click()
3.下拉框-----select与非select
select
- 定位这个select标签 以参数形式传递进去
-
以什么方式来选择下拉框的选项
# select标签
selectTag = Select(driver.find_element_by_class_name('nojs'))
# 选择方式
# 1 根据值来选择
selectTag.select_by_value('JP')
# 2 根据索引来选择
selectTag.select_by_index(2)
非select
- 先定位选择框的位置
- 再定位选项的位置
- 点击选项的位置
# 非select标签
# 1.定位选择框并点击
divTag = driver.find_element_by_id('dk_container_country_nofake').click()
# 2.定位到要选择值的位置并点击
driver.find_element_by_xpath('xpath路径').click()
4.翻页
在不知道有多少页数的情况下进行翻页
- 第一种:不断点击下一页,针对最后一页没有下一页的按钮
try:
# 找不到下一页,就是最后一页,就会抛出异常 此时就证明是最后一页了
driver.find_element_by_link_text('下一页').click()
except Exception as e:
driver.quit()
break
- 第二种:判断是否是最后一页,针对最后一页有下一页按钮,但是无法点击
while True:
self.pares_html()
# 在最后一页的时候,找到特殊的属性
if self.driver.page_source.find('pn-next disable') == -1:
self.driver.find_element_by_xpath(下一页的标签元素位置xpath路径).click()
time.sleep(1)
else:
self.driver.quit()
break
5.往下拉拖拽
- 针对那些ajax动态加载的网站,边往下拉,边生成响应文件
- 需要手动下拉加载全部的信息
- driver.execute_script(
‘window.scrollTo(0,document.body.scrollHeight)’
)
class Spider():
def pares_html(self):
# 进入这个页面的时候,把这个拖动条拖动一下,拖到最下面,把页面全部加载出来
# 0 是从去起始位置开始
# document.body.scrollHeight 整个窗口的高度
self.driver.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
time.sleep(3)
(六)其他操作
1.有iframe的标签------切换iframe
- frame 是HTML的标签 作用:文档中的文档 所以如果有iframe标签 而这个标签里面嵌套的内容正好就有你要操纵的元素,此时此刻就需要先切换iframe
- 不切换的话会报错,会找不到不要查询的元素
- 定位到你要操作的地方的iframe标签位置
driver.switch_to.frame(定位的位置)
driver.switch_to_frame(定位的位置) 过时,但是还是可以用
2.判断是否存在某字段
- driver.page_source.find
- driver.page_source.find(字段),用拿到的全部的网页信息来find我们要的信息,如果找不到会返回-1,找到的话返回的位置数字
-
区别:driver.find_element…这个没有找到会直接报错,可以和try except搭配,而driver.page_source.find找不到会返回-1
- 相同:最终element呈现的结果,也就是页面有的信息全都可以找到
if self.driver.page_source.find(标签里的字段) == -1: #判断该页面是否存在该标签
3.鼠标行为链
鼠标有啥行为和动作:双击、右键、单击、选中、拖拽…
-
from selenium.webdriver import ActionChains
-
实例化对象
- actions = ActionChains(driver)
-
提交行为链
- actions.perform()
实现所有行为链操作,最后要提交行为链,实施决策
-
传值
- inputTag = driver.find_element…
- actions.send_keys_to_element(inputTag,要传的值)
区别:普通的是inputTag.send_key()
-
点击
- buttonTag = driver.find_element…定位到的按钮标签位置
- actions.move_to_element(buttonTag) 将光标移动到按钮的位置
- actions.click() 执行点击动作
不能直接buttonTag.click(),不要在鼠标行为链里面出现,要放在提交行为链后面才能使用
-
更多的鼠标相关的操作
• click_and_hold(element):点击但不松开鼠标。
• context_click(element):右键点击。
• double_click(element):双击。
• 更多方法请参考:http://selenium-python.readthedocs.io/api.html
4.模拟登入
- 选择登入方式,多种多样,根据登陆页面相应操作后,左后点击登入按钮
- 输入账号密码/扫描/点击头像自动登入
账号密码登入
# 选择账号密码登入方式
driver.find_element_by_class_name('account-tab-account').click()
time.sleep(2)
# 定位账号和密码 并输入内容
driver.find_element_by_id('username').send_keys('xxxxxx')
time.sleep(1)
driver.find_element_by_id('password').send_keys('xxxxxx')
扫描登入
login_url = 'https://kyfw.12306.cn/otn/resources/login.html' # 登录的url
personal_url = 'https://kyfw.12306.cn/otn/view/index.html' # 个人中心的url
driver.get(login_url)
# 检测是否因为扫码成功url跳转到个人中心,登录也是一个耗时的操作
WebDriverWait(driver, 1000).until(
EC.url_contains(personal_url)
)
print('登录成功!')
点击头像自动登入
- 仅使用那些后台已经登入后,只需要点击头像就可以自动登陆,很多qq登陆会支持这个功能
# 只需要点击头像就可以登陆的url
driver.get('https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=手机QQ空间&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=https%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html&pt_no_auth=0')
# 等待加载出后台登陆的信息
time.sleep(1)
# 定位头像位置
button = driver.find_element_by_class_name('face')
# 点击头像即登陆
button.click()
5.get_cookies()获取cookie
- driver.get_cookies() 返回列表
- 作用:因为有些网页要登入才能访问,但过段时间cookie会失效,所以可以通过模拟登入来获取最新cookie
- 操作步骤:1 要通过selenium点击登入,并获取cookie值 2.解析这个cookie值 3.require请求头加入这个cookie
# 处理成可以用来爬虫的cookie信息cookie_str来模拟登入
listCookies = driver.get_cookies() 返回列表
cookie = [item['name'] + '=' + item['value'] for item in listCookies ] # cookies藏在name和value信息里
cookie_str = '; '.join(item for item in cookie)
四、wait页面等待
为什么要等?
- 1 selenium比较慢 网站打开了 元素没有加载出来
2 有些数据是通过ajax加载的
如何解决?
- time.sleep() 靠谱 Python提供的,强制等待
- selenium也提供了页面等待的方式,只要找到元素就立即执行,超过这个时间那么就抛出一个异常。
- 1.隐式等待:driver.implicitly_wait(秒数)全局的等待时间
- 2.显示等待:WebDriverWait(driver,秒数).until(条件) ,显示等待是表明某个条件成立后才执行获取元素的操作。
显示等待模块WebDriverWait与EC
- from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
- 常用的 EC.text_to_be_present_in_element_value
、EC.presence_of_element_located、EC.element_to_be_clickable、EC.url_contains()
(一)title标题
(1) EC.title_is :网页标题是否显示特定内容(必须完全符合),如果是返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.title_is(‘字段’))
result = EC.title_is('百度一下,你就知道')
print(result(self.driver)) # True
WebDriverWait(driver,2).until(result) # True
(2)EC.title_contains :网页标题是否包含特定内容,如果是返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.title_contains(‘字段’))
result = EC.title_contains('百度')
print(result(self.driver)) # True
WebDriverWait(driver,2).until(EC.title_contains('百度') # True
(二)url网址
(1)url_contains:url是否包含特定内容,如果是返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.title_contains(‘部分字段’)
result = EC.url_contains('baidu')
print(result(self.driver)) # True
WebDriverWait(driver,2).until(EC.title_contains('百度') # True
(2)url_matches:正则匹配url,网页网址是否匹配特定内容,如果是返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.url_matches(pattern))
- pattern是匹配url的正则表达式样式
#url是https://www.baidu.com/
pattern = r'.*?baidu.*?' #使用正则表达式,规定网址格式(格式要求以https开头)
result = EC.url_contains(pattern)
print(result(self.driver)) # True
WebDriverWait(driver,秒数).until(EC.url_matches(pattern)) # True
(3)url_to_be :网页网址是否显示特定网址(必须完全符合),如果是返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.url_to_be(url))
result = EC.url_to_be('https://www.baidu.com')
print(result(self.driver))
WebDriverWait(driver,秒数).until(EC.url_to_be('https://www.baidu.com'))
(三)element元素显示与可见
(1)presence_of_element_located: 特定元素是否存在于页面中,如果是,返回该元素(单个元素),否则报错
- WebDriverWait(driver,秒数).until(EC.presence_of_element_located(locator))
- locator = (By.CLASS_NAME, ‘lh’) # 类似的定位元素
locator = (By.CLASS_NAME, 'lh') #定位class='lh'的元素
result = EC.presence_of_element_located(locator)
print(result(self.driver))
WebDriverWait(driver,2).until(EC.presence_of_element_located(locator))
(2)presence_of_all_elements_located :定位的元素范围内,是否至少有一个元素存在于页面当中,如果是,返回满足条件的所有元素组成的List,否则返回空List
- WebDriverWait(driver,秒数).until(EC.presence_of_all_elements_located(locator))
locator = (By.CLASS_NAME, 'lh') #定位所有class='lh'的元素
result = EC.presence_of_all_elements_located(locator)
print(result(self.driver))
(3)visibility_of_element_located :特定元素是否存在于网页中并可见,如果是返回该元素(单个元素),否则报错
- WebDriverWait(driver,秒数).until(EC.visibility_of_element_located(locator))
locator = (By.CLASS_NAME, 'hl')
result = EC.visibility_of_element_located(locator)
print(result(self.driver))
WebDriverWait(driver,2).until(EC.visibility_of_element_located(locator))
元素可见:元素的高和宽都大于0
- 注:visibility_of_element_located与 presence_of_element_located作用类似,但前者无所谓可见与否,所以在性能上略胜一筹。
(4)invisibility_of_element_located: 特定元素是否不可访问或不存在于DOM树中,如果不存在则返回True,否则返回True
- 注:invisibility_of_element_located :刚好与 visibility_of_element_located的作用相反,且返回的结果大不相同。
(5)invisibility_of_element: 特定元素是否不可访问或不存在于DOM树中,如果不存在则返回True,否则返回True
- 注:invisibility_of_element_located与 invisibility_of_element作用类似,但前者传的是定位范围locator,后者可以是定位范围(仅text文本),也可以是元素element。
(6)visibility_of: 特定元素是否存在于DOM树中并可见,如果是返回该元素(单个元素),否则报错
element = self.driver.find_element_by_id('kw')
result = EC.visibility_of(element)
print(result(self.driver))
- 注:visibility_of_element_located与 visibility_of作用类似,但是前者传入的是定位范围locator,后者传入的是元素element,另外 invisibility_of_element与 visibility_of作用相反,且返回的结果大不相同。
(7)visibility_of_any_elements_located: 定位的元素范围内,是否至少有一个元素存在于DOM树中并可见,如果是,返回满足条件的所有元素组成的List,否则返回空List
(8)visibility_of_all_elements_located: 定位的元素范围内,是否所有元素都存在于DOM树中并且可见,如果是,以List形式返回元素,否则返回False
(9)element_to_be_clickable: 特定元素是否可点击,如果可以则返回该元素,否则返回False
- WebDriverWait(driver,秒数).until(EC.element_to_be_clickable(locator))
locator = (By.ID, 'su') #是一个可点击的按钮
result= EC.element_to_be_clickable(locator)
print(result(self.driver))
WebDriverWait(driver,2).until(EC.element_to_be_clickable(locator))
(四)text文本----element
(1)text_to_be_present_in_element:特定文本是否出现在特定元素中,如果是则返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.text_to_be_present_in_element(locator,文本))
locator = (By.ID, 'su')
element = EC.text_to_be_present_in_element(locator, 'submit') #查看中是否包含'submit'
print(element(driver))
WebDriverWait(driver,2).until(EC.text_to_be_present_in_element(locator, 'submit'))
(2)text_to_be_present_in_element_value:判断某文本是否是存在于特定元素的value值中,如果是则返回True,否则返回False
- WebDriverWait(driver,2).until(EC.text_to_be_present_in_element_value(locator, 属性value属性值) )
locator = (By.ID, 'su')
element = EC.text_to_be_present_in_element_value(locator, '百度一下') #查看的value值中是否包含'百度一下'
print(element(driver))
WebDriverWait(driver,2).until(EC.text_to_be_present_in_element_value(locator, '百度一下') )
- 注:如果该特定元素没有value值,也会返回False
(五)frame
(1)frame_to_be_available_and_switch_to_itframe:窗口是否可被切换,如果是返回True,否则返回False
- WebDriverWait(driver,2).until(EC.text_to_be_present_in_element_value(locator, ‘百度一下’) )
(六)windows窗口
(1)number_of_windows_to_be:特定窗口数和实际窗口数是否一致,如果是返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.number_of_windows_to_be(个数) )
windows = EC.number_of_windows_to_be(2) #期望窗口设置为2个
print(windows(self.driver))
WebDriverWait(driver,10).until(ECnumber_of_windows_to_be(2) )
(2)new_window_is_opened:新窗口是否打开,如果是返回True,否则返回False
- WebDriverWait(driver,秒数).until(EC.new_window_is_opened(driver.window_handles) )
current_handles = self.driver.window_handles #获得当前所有句柄数量
new_window = EC.new_window_is_opened(current_handles)
print(new_window(self.driver))
WebDriverWait(driver,10).until(EC.new_window_is_opened(current_handles) )
(七)alert对话框
(1)alert_is_present:弹出框是否存在,如果是,切换到alert,否则返回false
- WebDriverWait(driver,秒数).until(EC.alert_is_present() )
alert = EC.alert_is_present()
WebDriverWait(driver,秒数).until(EC.alert_is_present() )
#操作alert,例如:关闭alert
alert.accpet()
五、Selenium的常见错误
未联网
- Message: unknown error: net::ERR_INTERNET_DISCONNECTED
(Session info: chrome=90.0.4430.212)
没有切换iframe
- Message: no such element: Unable to locate element: {“method”:“css selector”,“selector”:".account-tab-account"}
(Session info: chrome=90.0.4430.212)
会报错说显示找不到元素
- 解决办法:查看定位的元素是否在iframe标签下,如果是,就要先定位iframe标签,并切换到该标签下,加上这两行就可以解决
- login_frame = driver.find_element_by_xpath(’//*[@id=“anony-reg-new”]/div/div[1]/iframe’) 括号填的就是iframe标签的xpath路径
driver.switch_to.frame(login_frame)
JS加载,hidden
按钮无法点击
- 有些按钮用Selenium就是无法点击没在这种情况下,我们采用其他办法
- 解决办法:
- btn = driver.find_element_by_id(‘query_ticket’)
driver.execute_script(‘arguments[0].click()’,btn) 固定的元素,使用这种方法点击代替btn.click()
元素无法传值
- type中含有hidden,无法传值
- driver.execute_script(‘arguments[0].value="%s"’ % 输入框的值, 输入框的定位元素对象)
六、Selenium的实例
(一)模拟登录—豆瓣和12306
模拟登录豆瓣
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
import time
driver = webdriver.Chrome(r"C:\Users\lenovo\Desktop\chromedriver.exe")
driver.get('https://www.douban.com/')
# 切换iframe
login_frame = driver.find_element_by_xpath('//*[@id="anony-reg-new"]/div/div[1]/iframe')
driver.switch_to.frame(login_frame)
# 切换登录方式 千万不要忘记click() 当属性有空格的时候 account-tab-account on 如何解决呢?1.可以选其中的一部分(通过测试)先选择长一点的尝试 2 xpath来定位
driver.find_element_by_class_name('account-tab-account').click()
time.sleep(2)
# 定位账号和密码 并输入内容
driver.find_element_by_id('username').send_keys('xxxxxx')
time.sleep(1)
driver.find_element_by_id('password').send_keys('xxxxxx')
# 点击登录按钮
driver.find_element_by_class_name('btn').click()
模拟登录12306
from selenium import webdriver
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
driver = webdriver.Chrome()
# 面向对象来实现
# 类是一个创建对象的对象 希望必须做一些事情 不做这个类就创建不成功
class TrainSpider(object):
login_url = 'https://kyfw.12306.cn/otn/resources/login.html' # 登录的url
personal_url = 'https://kyfw.12306.cn/otn/view/index.html' # 个人中心的url
def __init__(self,from_station,to_station,train_data):
self.from_station = from_station
self.to_station = to_station
self.train_data = train_data
def login(self):
driver.get(self.login_url)
# 登录也是一个耗时的操作
WebDriverWait(driver, 1000).until(
EC.url_contains(self.personal_url)
)
print('登录成功!')
# run一般用来封装了我们基本的功能
def run(self):
# 登录
self.login()
def main():
spider = TrainSpider('北京','长沙','2021-05-19')# 日期格式需要注意2021-05-19
spider.run()
if __name__ == '__main__':
main()
(二)获取cookie–模拟登入QQ空间
qq登入第三方界面:点击头像就可以登入的方式
from selenium import webdriver
from selenium.webdriver.common.by import By
import requests
import time
# 模拟登录QQ空间
# 携带cookie进行模拟 也就是我们先通过正常的途径进行登录此时此刻就可以获得一个cookie.然后在正常的编写一个 模拟登录的逻辑就可以啦
# 下面的逻辑 1 要通过selenium获取 qq空间的cookie值 2 解析这个cookie值 3 进行测试
driver = webdriver.Chrome(r"C:\Users\lenovo\Desktop\chromedriver.exe")
# 不要删参数 加载第三方的登录方式,需要后台登陆了qq
driver.get('https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=手机QQ空间&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=https%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html&pt_no_auth=0')
# 等待加载出登入的头像
time.sleep(2)
#点击登入的地方的标签
button = driver.find_element_by_class_name('face')
# 进行点击
button.click()
#等待登入界面打开
time.sleep(2)
#获取cookies
listCookies = driver.get_cookies()
cookie = [item['name'] + '=' + item['value'] for item in listCookies]
cookie_str = '; '.join(item for item in cookie)
# 目标url,登入界面
url = 'https://user.qzone.qq.com/自己的QQ号'
headers = {
'cookie':cookie_str,
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
}
html = requests.get(url,headers=headers)
time.sleep(2)
# 写入个人界面的源代码
with open('qzong.html','w',encoding='utf-8') as file_obj:
file_obj.write(html.text)
print(html.text)
(三)翻页–爬取猫眼电影
- 用到点击下一页的翻页
from selenium import webdriver
import csv
class maoyanSpider(object):
def __init__(self):
# 创建chrome设置对象 程序没有问题在去设置 无界面模式
self.options = webdriver.ChromeOptions()
# 设置无界面功能 --headless 浏览器无界面 --xxxx
self.options.add_argument('--headless')
self.driver = webdriver.Chrome(options=self.options)
self.driver.get('https://maoyan.com/board/4')
def get_one_page(self):
# 找到这一页的dd标签,就是电影的标签,找到dd不止一个用elements
movielist = []
dd_lst = self.driver.find_elements_by_xpath('//*[@id="app"]/div/div/div[1]/dl/dd')
for dd in dd_lst:
# text属性 获取当前dd节点的子节点以及后代节点的文本内容
# 视情况而分析 验证我们打印的内容有什么规律吗?如果有 就进一步操作
# 这里有规律,所以直接对字符串切分,然后通过序号索引就行
# print(dd.text)
# print('*'*80)
one_film_info_lst = dd.text.split('\n')
try:
rank = one_film_info_lst[0].strip()
name = one_film_info_lst[1].strip()
actor = one_film_info_lst[2].strip()
time = one_film_info_lst[3].strip()
score = one_film_info_lst[4].strip()
except:
pass
movielist.append((rank,name,actor,time,score))
return movielist
def saveData(self):
header = ['排名','电影名','演员','年份','评分']
with open('maoyanMovie.csv','w',encoding='utf-8',newline='') as file_obj:
writer = csv.writer(file_obj)
writer.writerow(header)
while True:
writer.writerows(self.get_one_page())
# 如果最后一定会报错的话,用try、except比if更好用
try:
# 找不到最后一页 就会抛出异常 此时就证明是最后一页了
self.driver.find_element_by_link_text('下一页').click()
except Exception as e:
driver.quit()
break
if __name__=='__main__':
main = maoyanSpider()
main.saveData()
(四)翻页拖拽–爬取京东商品信息
from selenium import webdriver
import time
import csv
class JdSpider():
def __init__(self,good_name):
self.good_name = good_name
# 设置无界面
self.options = webdriver.ChromeOptions()
# 设置无界面功能 --headless 浏览器无界面 --xxxx
self.options.add_argument('--headless')
self.driver = webdriver.Chrome(options=self.options)
self.driver.get('https://www.jd.com/')
# 定位输入框和按钮
self.driver.find_element_by_xpath('//*[@id="key"]').send_keys(self.good_name)
time.sleep(1)
self.driver.find_element_by_xpath('//*[@id="search"]/div/div[2]/button').click()
time.sleep(1)
def pares_html(self):
# 进入这个页面的时候,把这个拖动条拖动一下,拖到最下面
# 0 是从去起始位置开始
# document.body.scrollHeight 整个窗口的高度
self.driver.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
time.sleep(3)
# 提取数据 千万不要忘记写li
li_lst = self.driver.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li')
item = []
for li in li_lst:
# print(li.text)
# print('*'*50)
try:
price = li.find_element_by_xpath('.//div[@class="p-price"]/strong').text.strip()
name = li.find_element_by_xpath('.//div[@class="p-name"]/a/em').text.strip()
commit = li.find_element_by_xpath('.//div[@class="p-commit"]/strong').text.strip()
shop = li.find_element_by_xpath('.//div[@class="p-shopnum"]/a').text.strip()
except Exception as e:
print(e)
item.append((price,name,commit,shop))
return item
def saveData(self):
header = ['价格','商品名','评价','店铺']
with open('JD'+self.good_name+'.csv','w',encoding='utf-8',newline='') as file_obj:
writer = csv.writer(file_obj)
writer.writerow(header)
while True:
writer.writerows(self.pares_html())
# 如果最后一定会报错的话,用try、except比if更好用
# 这个代码是一直爬取到最后一页,如果不需要那么多可以手动停止,或者改成爬取页面页数限制
if self.driver.page_source.find('pn-next disable') == -1:
self.driver.find_element_by_xpath('//*[@id="J_bottomPage"]/span[1]/a[9]').click()
time.sleep(1)
else:
self.driver.quit()
break
if __name__ == '__main__':
good_name = input('请输入你要查询的商品的关键字:')
spider = JdSpider(good_name)
spider.saveData()
(五)关闭弹窗+显示等待+按钮无法点击–爬取12306网站信息
from selenium import webdriver
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
driver = webdriver.Chrome()
# 隐式等待
driver.get('https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc')
driver.implicitly_wait(3)
# 关闭提示框
driver.find_element_by_id('gb_closeDefaultWarningWindowDialog_id').click()
# 显示等待,等待出发地加载出来,这个时候你需要自己手动的在页面添加城市信息,当页面检测出来后,就会自动的弹出车次信息
WebDriverWait(driver,1000).until(
EC.text_to_be_present_in_element_value((By.ID,'fromStationText'),'北京')
)
# 等待目的地加载出啦
WebDriverWait(driver,1000).until(
EC.text_to_be_present_in_element_value((By.ID,'toStationText'),'长沙')
)
btn = driver.find_element_by_id('query_ticket')
# 按钮不能够被点击
driver.execute_script('arguments[0].click()',btn)
# btn.click()