python selenium 练习 自动获取豆瓣阅读当前特价书籍 chrome 元素定位 窗口切换 元素过期
豆瓣原创电子书每周推出数十本限时免费数目,一周免费期过后恢复原价。想着豆瓣原创书中有不少值得一看,便写了个脚本,免去一个个添加的烦恼。
使用了Windows下selenium+Python的组合,有较多的文档可以查阅,主要总结如下:
1、使用chrome浏览器:下载旧版本(52),新版本不兼容,下载chromedriver,放入chrome安装目录,于chrome.exe同目录,并添加到Path环境变量。
2、强大的元素定位:通过浏览器审查元素直接复制的xpath多为绝对定位,容易受网页结构调整的影响,稳定性不好。
相对定位在确保唯一性的前提下,可以自己写,快准稳。一般通过@id段确保唯一,注意同类型list集的影响。
xpath中by_link_text可以通过链接文字直接定位<a>元素,在用到特殊链接时很有效。
by_xpath("//*[text()='限时特价']") 这个简直简单粗暴,直接定位文字内容。有点JS里innerHTML的意思。
3、标签页的切换:用handles = driver.window_handles 获取当前的标签页,再通过driver.switch_to.window(handles[1]) 切换。
4、元素过期:翻页和刷新页面后再获取元素,频频报错。一方面,刷新页面后必须进行新的元素获取,并操作新获取的元素,尽量把获取写在循环体内。
另一方面,页面刷新时,网页的代码执行速度比网页渲染速度快,下面代码采取time.sleep(2)简单粗暴,强制延迟等待网页渲染完毕,再进行元素获取,否则报错元素不存在,或元素过期。
import selenium import time from selenium import webdriver from selenium.webdriver.common.keys import Keys driver=webdriver.Chrome() #打开豆瓣主站 driver.get('https://www.douban.com/') #最大化 driver.maximize_window() #输入用户名,密码 driver.find_element_by_id('form_email').send_keys('********') driver.find_element_by_id('form_password').send_keys('******') #点击登录 time.sleep(1) driver.find_element_by_xpath('//*[@id="lzform"]/fieldset/div[3]/input').click() time.sleep(3) #打开阅读 driver.find_element_by_xpath('//*[@id="db-global-nav"]/div/div[4]/ul/li[7]/a').click() time.sleep(2) #切换到新打开的窗口 handles = driver.window_handles driver.switch_to.window(handles[1]) time.sleep(2) #打开免费 driver.find_element_by_link_text('免费').click() time.sleep(2) #需要爬的页数 page=3 #已购买数量 book_is_read=0 #未购买数量 book_not_read=0 #外循环循环翻页 for j in range(0,page+1): #本页循环数量 page_end=0 thisbooklist=0 time.sleep(2) #内循环循环本页20条 for i in range(0,20): time.sleep(2) #只爬每周限时可选 driver.find_element_by_xpath("//*[text()='限时特价']").click() time.sleep(2) #获取本页书籍列表 booklists=driver.find_elements_by_xpath("//li[@class='item store-item']") page_end=0 for booklist in booklists: #获取阅读标志 isread=booklist.find_element_by_xpath(".//div[@class='action-buttons']/a").get_attribute("class") #检查是否已经购买 if 'read' in isread: page_end=page_end+1 continue thisbooklist=booklist break #循环至列表最后一项跳出循环 if page_end>19:break #进入书籍详情 thisbooklist.find_element_by_xpath('.//div[1]/a/img').click() time.sleep(1) #点击购买 driver.find_element_by_xpath("//span[@class='icon-add-to-bookshelf']").click() #点击确定 time.sleep(2) driver.find_element_by_xpath("//*[@id='ark-dialog']/div[2]/div[2]/button[1]").click() time.sleep(3) #返回上一页 driver.back() time.sleep(2) #刷新 driver.refresh() # 打开下一页 time.sleep(2) #翻页 driver.find_element_by_xpath('/html/body/div/div/article/div[2]/div[2]/div/ul/li[10]/a').click() time.sleep(2) driver.close()