Selenium入门:爬取王者营地96英雄背景故事及技能信息

写在前面:

  1. 确实在需求面前去学习会比较有效果…硬记一条条语句不仅慢,,用的时候还要想“这为啥又不行…”
  2. 本来是想从知乎动手的…但是登陆都没做到emm…昨天还以为知乎很nb,selenium的反爬也太厉害了吧,然后做完这个之后才知道和人家没关系 只是因为自己啥也不会 是个憨憨…

代码

直接贴代码了,反正为了以后自己能看明白自己这毫无逻辑的代码,每一行都强行注释上了

	from selenium import webdriver
	import time
	from selenium.webdriver.common.action_chains import ActionChains #用于实现鼠标悬停,改变特定div的display
	
	#内容以字符串格式写入文档
	def strWrite(url,text):
	    try:
	        f=open(url,'a',encoding='utf-8')
	        f.write(text+'\n')
	        f.close()
	    except Exception as ex:
	        print('写入出错')
	
	
	#程序开头selenium打开浏览器,找到包含所需内容的一些操作
	def mainProgram():
	    driver.maximize_window()#当前窗口最大化
	    driver.get('http://www.baidu.com')#进入百度
	
	    kw = driver.find_element_by_id('kw')#通过id找到百度输入框
	    kw.send_keys('王者营地')#搜索关键字通过send_keys('')
	    su = driver.find_element_by_id('su')#通过id找到百度搜索按钮
	    su.click()#点击搜索按钮
	    time.sleep(2)#等待2s
	
	    wzyd = driver.find_element_by_link_text('《王者荣耀助手》正式升级为《王者营地》-王者荣耀官方网站-腾讯...')#通过标签内容文字找到王者营地的官网
	    wzyd.click()#点击王者营地官网
	    time.sleep(5)#等待5s
	
	    driver.switch_to.window(driver.window_handles[1])  # 因为点击官网进入新的标签页,此语句进入所有页面里下标为1的页面
	    yxzl = driver.find_element_by_css_selector('.main-nav > li:nth-child(2) > a')#在表头找到“游戏资料”
	    yxzl.click()#点击“游戏资料”
	
	    time.sleep(3)#等待3s
	    driver.switch_to.window(driver.window_handles[2]) # 因为点击游戏资料进入新的标签页,此语句进入所有页面里下标为2的页面
	    js = "var q=document.documentElement.scrollTop=900"#js语句 将页面右方拖动条拖动至距离顶部900px的位置
	    driver.execute_script(js)#webdriver执行上一条js语句
	    allHeroSkills()#开始读取全部英雄的技能信息!(和他们的背景故事)
	
	#一个英雄的特定技能的读取
	def skills(num):
	    page=num-1#这里的page不要理解为页码,理解为“技能page”,如“技能1”,“技能2”。。存在原因是因为“技能0”听起来怪怪的,
	    #所以选择不用下标
	
	    ele = driver.find_elements_by_css_selector('html body div.wrapper div.zkcontent div.zk-con-box div.zk-con3.zk-con div.skill.ls.fl div.skill-info.l.info ul.skill-u1 li')
	    #找到技能栏那些技能的《li》标签的列表
	    ActionChains(driver).move_to_element(ele[page]).perform()#通过函数传进来的num,用这条语句实现鼠标停留在某一个指定技能上
	    oneskill_name=driver.find_elements_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div/div/div[{0}]/p[1]/b'.format(num))[0].text
	    #找到技能名称
	    oneskill_cd=driver.find_elements_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div/div/div[{0}]/p[1]/span'.format(num))[0].text
	    #找到技能冷却时间,CD
	    oneskill_blue=driver.find_elements_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div/div/div[{0}]/p[1]/span'.format(num))[1].text
	    #找到技能消耗的蓝量
	    oneskill_introduce=driver.find_elements_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div/div/div[{0}]/p[2]'.format(num))[0].text
	    #找到技能的具体介绍
	    oneskill_tips=driver.find_elements_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[2]/div/div/div[{0}]/div'.format(num))[0].text
	    #找到技能的小技巧(来自官方的小技巧可能会没什么卵用...)
	    strWrite(r'C:\Users\lcega\Desktop\1233.txt',oneskill_name+'   '+oneskill_cd+' '+oneskill_blue)#技能,cd,耗蓝放在一行输出,搭配strWrite函数写入指定地址的某个txt里
	    strWrite(r'C:\Users\lcega\Desktop\1233.txt',oneskill_introduce)#技能介绍写入txt (strwrite里添加了‘每写一次最后都加个换行符’,贼关键
	    strWrite(r'C:\Users\lcega\Desktop\1233.txt',oneskill_tips)#技能小提示写入txt
	
	#通过函数名应该也能看懂我什么意思————————为了(for)代码量更少(less)而去(to)构造一个函数(circle),哈哈哈哈哈哈哈我真特娘是个人才
	def forlesstoCircle(i):
	    time.sleep(1)#等待1s
	    for handle in driver.window_handles:
	        driver.switch_to.window(handle)#从现有网页开始一个个选中(最后必然是选中所有网页中打开时间最短的那个网页)
	    time.sleep(1)#等待1s
	
	    herostory = driver.find_element_by_xpath('/html/body/div[3]/div[1]/div/div/div[1]/div[2]/a[1]')#找到英雄故事那个按钮
	    herostory.click()#点击英雄背景故事按钮
	    storycontent = driver.find_elements_by_xpath('/html/body/div[4]/div[2]/p')#找到英雄背景故事内容存放位置。
	    #至于上几行 为啥要点那个按钮 因为要把包含背景故事的节点的祖宗节点的display改成block了才能xpath找到....可能不用,但是我今天刚学我只会这么解决。
	    for j in range(len(storycontent)):
	        strWrite(r'C:\Users\lcega\Desktop\1233.txt',storycontent[j].text)#背景故事的格式不统一也是个坑。。。有的是一个《p》里靠br换行,,有的是好几个《p》
	    #里面甚至还带着《b》
	
	    time.sleep(1)#等待1s
	    for handle in driver.window_handles:  # 始终获得当前最新的窗口
	        driver.switch_to.window(handle)
	    driver.find_element_by_xpath('/html/body/div[4]/div[1]/a').click()#单击弹出div的小叉叉,如果没有上一步重新选中当前窗口,就点不了,这也是个坑...
	
	    js = "var q=document.documentElement.scrollTop=400"#js语句,页面滑动到距离页面顶端400px的位置
	    driver.execute_script(js)#执行上一句js
	
	    skills(1) #读取技能1并存起来!!(就是被动那里...)
	    skills(2)#读取技能2并存起来!!   (实际上这才是1技能,比如孙尚香翻滚,干将护主邪冢那个击飞...)
	    skills(3)#读取技能3并存起来!!(实际上这才是2技能)
	    skills(4)#读取技能4并存起来!!(实际上这才是3技能)
	    fiveskillhero_list=[6,10,13,16,24,31,33,56]#(带被动总共5个技能的英雄要特殊处理....)
	    #盘古,李信,盾山,元歌,女娲,干将,大乔,兰陵王
	    if (i in fiveskillhero_list):#如果有5技能,就读取.....
	        skills(5)
	    time.sleep(1)#等待1s
	    driver.close()#关闭浏览器当前页面,,,如果想关所有页面用quit(),这个代码没用上
	    strWrite(r'C:\Users\lcega\Desktop\1233.txt', '\n\n\n')#每个英雄的背景故事和信息之间都间隔上3行,方便看
	    print('成功录入该英雄背景故事及技能详情,当前共计录入{0}位英雄'.format(i))#用于pycharm上方便看到哪一个英雄了,或者说白了,,到哪儿出问题了
	
	#处理所有英雄的所有技能!!(以及他们的背景故事)
	def allHeroSkills():
	    time.sleep(1)#等待1s
	    for i in range(1,61):#我的屏幕大小下移900后,最多能显示前60位英雄的头像(可供点击)
	        for handle in driver.window_handles:  # 一样,出现过很多回了 始终获得当前最后的窗口  每一次循环都来一次的原因是
	            driver.switch_to.window(handle)#driver.close()关闭一个窗口的时候,任何窗口都未被选中。。。
	        hero = driver.find_element_by_css_selector('.herolist > li:nth-child({0}) > a:nth-child(1) > img:nth-child(1)'.format(i))#通过循环来决定到哪个英雄了
	        hero.click()#点击这个英雄的头像
	        forlesstoCircle(i)#上面出现的强行封装函数
	    for handle in driver.window_handles: # 一样,出现过很多回了 始终获得当前最后的窗口  出现在这里的原因是方便下面的滑动,不选中页面 js也失效
	        driver.switch_to.window(handle)
	    js = "var q=document.documentElement.scrollTop=1500"    #js语句,页面滑动到距离页面顶端1500px的位置 刚刚移动了900,需要再移600(为啥600,我自己测的),所以900+600=1500
	    driver.execute_script(js)#执行上面的js语句
	    for i in range(61,97):#滑动右方的条以后,可以找到剩下那些英雄啦
	        for handle in driver.window_handles:  # 一样,出现过很多回了 始终获得当前最后的窗口  出现在这里的原因是...0.0(忘了,可能我是个憨憨)
	            driver.switch_to.window(handle)
	        hero = driver.find_element_by_css_selector('.herolist > li:nth-child({0}) > a:nth-child(1) > img:nth-child(1)'.format(i))#通过循环来决定到哪个英雄了
	        hero.click()#点击这个英雄的头像
	        forlesstoCircle(i)#
	
	
	#主函数main 
	driver = webdriver.Firefox() 
	mainProgram()  #开始主函数

成品

Selenium入门:爬取王者营地96英雄背景故事及技能信息_第1张图片


注意事项

过程中一些因为不懂selenium的规则 进度停滞的地方 记下来:

  1. 当打开新页面或有需要刷新的时候,一定要通过等待页面加载出来再点击…
    ①sleep(time)

     import time
     time.sleep(10)
     强制等待时间。不管浏览器是否加载完成,都必须强制等待10s时间
    

    ②implicity_wait(time)

     隐性等待是浏览器在time时间内加载完成则继续执行。
     隐性等待对整个driver都有作用,只需要设置一次
    
  2. 打开新页面的时候,对新页面操作前要先选中新页面(同理关闭)。

     driver.switch_to.window(driver.window_handles[1])#中括号内数字为页面下标0,1,2,3....
    

    或者

      for handle in driver.window_handles:
      driver.switch_to.window(handle)#从现有网页开始一个个选中
      (最后必然是选中所有网页中打开时间最短的那个网页)
    
  3. 滑动滚轮功能(没显示在屏幕里的元素不能点,通过这个功能让未显示的显示…如果其实能点当我没说…)
    让driver执行js语句达到效果

     js = "var q=document.documentElement.scrollTop=900"#js语句 将页面右方拖动条拖动至距离
     顶部900px的位置
     driver.execute_script(js)#webdriver执行上一条js语句	
    
  4. selenium操作display=none的标签 css xpath什么的都找不到,必须先模拟用户操作改变对应的display才能进行下一步

    ①页面的点击弹出div,selenium操作的时候 弹出以后需要用第二条重新选中当前页面,不然关闭的小叉叉不好使。
    ②靠鼠标悬浮改变固定位置的div显示,可以通过将鼠标悬停在某位置

    	from selenium.webdriver.common.action_chains import ActionChains 
    	ele = driver.find_elements_by_css_selector('  ')
        ActionChains(driver).move_to_element(ele[page]).perform()
    

写在后面

虽然可能很low,也有很多错误,而且我在结束之后还去搜了搜 “selenium爬虫的意义”…
但是好歹也算是入了门,之后被问起,也能说一句了解了

你可能感兴趣的:(python)