一、主体思路
一般的Python爬虫设计采用的是requests库,此方法的特点是利用程序代码模拟http请求进行访问,但是主要问题是,在一些反爬虫网站中能够监测出requests模拟请求,即使是伪装了请求头heads。另外这种方法遇到的最大问题是网站采用加密进行传输数据。例如在一些网站中,表格数据采用ajax异步传输模式,而且在 request和response中都进行了md5加密,这样就需要深入分析js文件,查找加密算法,这个有一定的难度,很难完成。
基于原因,可以采用selenium进行模拟浏览器操作,相当于用代码打开一个浏览器,然后用代码控制 浏览器中网页的访问,例如屏幕下滑、点击按钮,提交表单等。这样就可以完成模拟人的操作模式request数据,然后 从浏览器收到的response中进行数据分析。这样就可以避开加密和解密的过程。
二、selenium遇到的几个坑
(1)selenium方法的主要缺点是速度不能过快,需要浏览器进行页面加载只有加载完成了才能进行数据分析。
(2)页面等待的有三种方法,一是简单的就是添加sleep延时,根据经验控制延时。二是利用wait函数进行控制,等待某个元素加载完成,适用于异步传输。三是统一声明页面重新加载默认时间,如果加载成功就继续,没有就等待到时间截止,这种适用于静态网页,不能用于动态的异步传输网页
(3)最大的坑,异步传输遇到一个表格要点击下一页,这个是ajax异步传输,但是它在页面底部,必须用代码控制页面滚动到底部才能用代码点击这个按钮。最开始没有滑动页面,导致始终报click点击错误。
(4)很多网站都进行了反爬虫,现在这个任务是爬3万多个页面,最开始速度过快,导致爬了40多页就被网站封了IP。后来进行了延时,主要延时是模拟人的操作特点,新页面加载后要延时,滑动页面后要延时、最重要的点击“下一页”后一定也要延时,感觉就是页面的停顿跟人操作一下个效果。目前一个页面4秒左右,没有问题。
(5)不要并发访问同一个网站,虽然用了不同的程序,但是IP地址没变,还是会被发现的。
(6)网站可以反爬selenium,就是在客户端的js中隐含一个selenium检测语句,目前网上提供的配置Chrome浏览器参数的方案都是不行的。看资料是说利用ip动态代理才能解决,有一定的难度,目前没有遇到这种反爬技术。
(7)用Chrome浏览器需要下载一个浏览器模拟驱动器,网上搜索就可以了。注意Chrome的版本要跟驱动器的版本一致,目前最新是版本 81.0.4044.138(正式版本) (64 位)
三、基本步骤
(1)定义浏览器对象:driver = webdriver.Chrome(),注意浏览器的模拟驱动器文件最简单方法就是放在和py文件一个文件夹中就可以了。
(2)访问页面 :driver.get(myurl)#访问网页,要等到页面加载完成
(3)找页面元素:利用id,tag,class,text等进行元素查找。只有等页面加载完成了才可以访问到元素。例如等待方法,X1=WebDriverWait(driver,10).until(EC.presence_of_element_located((By.CLASS_NAME, "fypages")) )#等待元素加载。
(4)操作元素:例如点击x1.click(),或者利用x1.click()分析网页数据
(5)窗口操作:例如 ,滑动页面到底部, driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 异步提交,必须把页面滚到最底部
(6)关闭浏览器:driver.quit()# 关闭浏览器
基于selenium的模拟浏览器操作爬虫
三、案例代码
目标网站不提供给大家了,自己分析代码吧。
from selenium import webdriverfrom time import sleepfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECmycount=0myshengfen=["陕西","内蒙古","辽宁","吉林"]myshengfencount=[1258,347,1348,1234]#存储数据到文件中,以json格式存储。def myfun1(mystr,myfilename): mystr001=str(mystr).split("") global mycount pass myfilename2=myfilename+"_data_2018_001.txt" myfile = open(myfilename2, "a", encoding="utf-8") for k in range(1,len(mystr001)): myl0=mystr001[k].split(" ") mydict001={} mydict001["school_name"]=myl0[0] mydict001["zhuanye"] = myl0[1] mydict001["shengfen"] = myl0[2] mydict001["kaosheng"] = myl0[3] mydict001["pici"] = myl0[4] mydict001["ave_value"] = myl0[5] mydict001["min_value"] = myl0[6] mydict001["leixing"] = myl0[7] mydict001["year"] = 2018 myfile.write(str(mydict001)+"") print(mycount,k,str(mydict001)+"") mycount=mycount+1 myfile.close()#访问网站# 后面是你的浏览器驱动位置,记得前面加r'','r'是防止字符转义的for ii in range(0,len(myshengfen)): driver = webdriver.Chrome() myurl=r"XXXXXXXXXXX"+myshengfen[ii]+r"&schoolyear=2018" #网站地址,自己更换就可以了 driver.get(myurl)#访问网页 sleep(5) #延时 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")#异步提交,必须把页面滚到最底部 sleep(2) mydata=[] for j in range(0,myshengfencount[ii]): try: print("点击一下页后") WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, "fypages")) )#等待元素加载 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 异步提交,必须把页面滚到最底部 driver.page_source # 异步更新数据源 x1=WebDriverWait(driver,10).until(EC.presence_of_element_located((By.CLASS_NAME,"search-table")) ) except: print("没有发现页面") #文本处理 myfun1(x1.text,myshengfen[ii]) print(myshengfen[ii],myshengfencount[ii],"1-页码:",j+1," ===x1"*10) x3=driver.find_element_by_class_name("fypages")#查找class元素 x4=x3.find_elements_by_tag_name("li")#利用tag查找元素 for i in x4: print(i.text) if i.text=='下一页': new=i.click()#模拟点击按钮 sleep(3) WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, "fypages")) ) #driver.page_source #异步更新数据源 ##sleep(1) driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 异步提交,必须把页面滚到最底部 #sleep(1) driver.page_source # 异步更新数据源 print("点击完下一页") break # driver.quit()# 关闭浏览器 print(myshengfen[ii],myshengfencount[ii],"1成功了--结束了")