Python3 之 模拟浏览器

本文介绍了如何使用Selenium和ChromeDriver处理AJAX请求时的身份验证Token问题,通过模拟浏览器操作获取已加载的内容,以及如何在Python中使用XPath和BeautifulSoup4在网页中查找和获取元素,包括注意事项和示例代码。
摘要由CSDN通过智能技术生成

        有一些网站在发起AJAX请求的时候,会带上特殊的字符串用于身份验证。这种字符串称为Token。虽然在网页的源代码中无法看到被异步加载的内容,但是在Chrome的开发者工具的“Elements”选项卡下却可以看到网页上的内容,这就说明Chrome开发者工具“Elements”选项卡里面的HTML代码和网页源代码中的HTML代码是不一样的。在开发者工具中,此时显示的内容是已经加载完成的内容。如果能够获得这个被加载的内容,那么就能绕过手动构造认证token的过程,可以直接使用XPath来获得想要的内容。
        这种情况下,就需要使用Selenium操作浏览器来解析JavaScript,再爬取被解析以后的代码。Selenium是一个网页自动化测试工具,可以通过代码来操作网页上的各个元素。Selenium是Python中的第三方库,可以实现用Python来操作网页。

        使用pip安装Selenium:

pip install selenium

        安装好之后,下载ChromeDriver,根据自己的系统选择合适的版本。官方网址:

​https://chromedriver.storage.googleapis.com/index.html​

        下载下来的是一个.zip压缩文件,解压以后是一个可执行文件。对于Mac OS和Linux,这个可执行文件就是chromedriver,没有后缀名。对于Windows,这个可执行文件的名称为chromedriver.exe。
        ChromeDriver是Chrome浏览器的一个驱动程序,因此要使ChromeDriver正常工作,还必须保证计算机上有Google Chrome浏览器。如果没有的话,百度搜索并下载即可。
        Selenium需要使用WebDriver才能处理网页,这里的WebDriver可以理解为浏览器或者浏览器驱动程序。它可以是Firefox,可以是Chrome,也可以是PhantomJS。其中前两者是有界面的,在处理网页的时候会弹出一个浏览器窗口,使用者可以很直观地看到网页的内容是如何被自动操作的。而PhantomJS是没有界面的,因此适合在服务器上使用。

1. Selenium的使用之获取源代码
        将chromedriver与代码放在同一个文件夹中以方便代码直接调用。初始化Selenium只需要两行代码,导入Selenium库,再指定WebDriver。

        第3行代码指定了Selenium使用ChromeDriver来操作Chrome解析网页,括号里的参数就是ChromeDriver可执行文件的地址。
        如果要使用PhantomJS,只需要修改第3行代码即可:
driver = webdriver.PhantomJS('./phantomjs')
        同样,需要将PhantomJS的可执行文件与代码放在一起。
需要特别提醒的是,如果chromedriver与代码不在一起,可以通过绝对路径来指定,例如:
driver = webdriver.Chrome('/usr/bin/chromedriver')
        使用Windows的开发者在写这个参数的时候,要注意反斜杠的问题。“\”这个符号叫作反斜杠,在Windows中作为路径的分隔符。但是由于转义字符也是反斜杠,所以如果把Windows下面的代码写为下面这样就会出问题。
driver = webdriver.Chrome('C:\server\chromedriver.exe')
        因此,使用Windows的读者可在路径字符串左引号的左边加一个“r”符号,将代码写为:
driver = webdriver.Chrome(r'C:\server\chromedriver.exe')
        这样Python就能正确处理反斜杠的问题。
初始化完成以后,就可以使用Selenium打开网页了。要打开一个网页只需要一行代码:
driver.get('http://test.com/index.html')
代码运行以后会自动打开一个Chrome窗口,并在窗口里面自动进入这个网址对应的页面。一旦被异步加载的内容已经出现在了这个自动打开的Chrome窗口中,那么此时使用下列代码:
html = driver.page_source
就能得到在Chrome开发者工具中出现的HTML代码,在ChromeDriver加载页面完成以后可以得到加载以后的源代码。

        设置了一个5s的延迟,这是由于Selenium并不会等待网页加载完成再执行后面的代码。它只是向ChromeDriver发送了一个命令,让ChromeDriver打开某个网页。至于网页要开多久,Selenium并不关心。由于被异步加载的内容会延迟出现,因此需要等待它出现以后再开始抓取。
假设设置为time.sleep(5),即强制等待5s,但是网页只用了1s就加载完成了,那么剩下的4s就浪费了。如果网页需要10s才加载完成,那么只等5s又不够,内容不全。
        为了让Selenium智能地等待网页加载完成,就需要使用“WebDriverWait”“By”和“expected_conditions”这3个关键字。来看看下面这一段代码:

    关键字WebDriverWait会阻塞程序的运行,它的第2个参数30表示最多等待30s。在这30s内,每0.5s检查一次网页。
    until在英文中的意思为“直到”,所以WebDriverWait会在30s内不停地检查网页元素,直到某个条件满足才会继续运行后面的代码。如果等待的内容始终不出现,那么30s以后就会抛出一个超时的Exception。
    而这个被等待的条件,就是expected_conditions,其中,expected的英文含义为“期待”,conditions的英文意思为“条件”。所以这个关键字表示期待某个条件。而这个条件就是“presence_of_element_located”,其中的“located”是“locate”的被动式,表示“被定位的”,“presence”的英文意思是“出现”。所以这个方法的作用是“被定位的元素出现”。而被定位的元素怎么定位呢?通过“By”这个关键字来指定class为“content”的这个元素。
    所以这段代码的意思是:“等待网页加载,直到class为content的HTML元素出现,如果30s都等不到,就抛出异常”。
    期望的条件除了某个元素出现以外,也可能是某个元素的text里面出现了某些文本:
WebDriverWait(driver, 30).until(EC.text_to_be_present_in_element((By.CLASS_NAME, "content"), '通关'))
    这句代码的意思是:等待网页加载,直到class为content的HTML元素里面的文本中包含了“通关”两个汉字。
    By除了指定class以外,还可以指定很多其他的属性,例如:

By.ID 
By.NAME


    当然,也可以使用XPath,即:

By.XPATH


    例如:

EC.presence_of_element_located((By.XPATH, '//div[@class="content"]'))

    特别提醒:“presence_of_element_located”的参数是一个元组,元组第0项为By.XX,第1项为具体内容。“text_to_be_present_in_element”的参数有两个:第1个参数为一个元组,元组第0项为By.xx,第1项为具体标签内容;第2个参数为部分或全部文本,又或者是一段正则表达式。

2. 在网页中获取元素
        在网页中寻找需要的内容,可以使用类似于Beautiful Soup4 的语法:

element = driver.find_element_by_id("passwd-id") #如果有多个符合条件的,返回第1个 
element = driver.find_element_by_name("passwd") #如果有多个符合条件的,返回第1个 
element_list = driver.find_elements_by_id("passwd-id") #以列表形式返回所有的符合条件的element 
element_list = driver.find_elements_by_name("passwd") #以列表形式返回所有的符合条件的element

        也可以使用XPath:

element = driver.find_element_by_xpath("//input[@id='passwd-id']")   #如果有多个符合条件的,返回第1个 
element = driver.find_elements_by_xpath("//div[@id='passwd-id']")   #以列表形式返回所有的符合条件的element

        但是有以下两点需要特别注意。
        (1)如果能找到元素,“find_element_by_xxx”返回的内容是一个Element对象;如果找不到元素,那么“find_element_by_xxx”将会抛出一个Exception。因此如果不确定元素是否存在,那么必须使用“try...except Exception”把“find_element_by_xxx”包起来。而如果使用“find_elements_by_xxx”,那么返回的是一个列表,列表里面是0个、1个或者多个Element对象。也就是说,即使找不到元素,也会返回一个空列表,程序不会抛出异常。
        (2)如果使用XPath,无论是“find_element_by_xpath”还是“find_elements_by_xpath”,只要是想获取HTML标签里面的文本信息,那么就不能在XPath的末尾加上“text()”。必须先使用“find_element_by_xpath”定位到文本所在的标签,然后读取返回的Element对象的“.text”属性;或者使用for循环展开“find_elements_by_xpath”返回的列表,得到每一个Element对象并读取它们的“.text”属性。如果把代码写为:

comment = driver.find_element_by_xpath('//div[@class="content"]/text()') 
comments = driver.find_elements_by_xpath('//div[@class="content"]/text()')

        程序就会报错。正确的写法应该是:
 

comment = driver.find_element_by_xpath('//div[@class="content"]') 
print(comment.text)  
comment = driver.find_elements_by_xpath('//p[starts-with(@id, "content_")]') 
for  each in  comment: 
    print(each.text)

--------------------------------------

没有自由的秩序和没有秩序的自由,同样具有破坏性。

--------------------------------------

  • 12
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值