python 爬虫(十)selenium+phantomjs请求页面流程 + selenium的三种等待 + 案例(豆瓣读书 + 腾讯招聘)

一、selenium+phantomjs来请页面的流程


1. 导包


from selenium import webdriver

2. 创建driver对象


driver = webdriver.Phantomjs()

3. 请求url


driver.get(url)

4. 等待


time.sleep(5)

等待有三种:

(1)强制等待:
time.sleep(10)
(2)隐式等待
driver.implicitly_wait(10)
隐式等待就是等到页面全部加载完成,比如js,css或者图片全请求到加载到页面,也就是我们常看到的页面不在转圈圈为止,程序才会继续运行。
(3)显示等待。
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
步骤:
1.创建等待对象
wait = WebDriverWait(
driver,#浏览器驱动对象
10,最大等待时长
0.5,扫描间隔
)
2.wait.until(等待条件)—>等待条件成立程序才继续运行。
等待条件在selenium中有个专门的模块来设置了一些条件—expected_conditions as EC
最常用的条件有一下两个:
EC.presence_of_element_located
EC.presence_of_all_elements_located
这两个条件验证元素是否出现,传入的参数都是元组类型的locator,如(By.ID, ‘kw’)
一个只要一个符合条件的元素加载出来就通过;
另一个必须所有符合条件的元素都加载出来才行
EC.presence_of_element_located(locator对象也就是定位器)
licator对象是一个元组(
通过什么来查找,–By.ID,By.XPATH,By.CSS_SELECTOR
‘查找的内容的语法’)
3.wait.until方法的返回值是一个对应定位器所定位到的webelement对象。你如果需要对这个webelment对象做一些点击或者其他操作,可以很方便的做到。


4. 获取页面内容


html = driver.page_source

5. 用lxml模块解析页面内容


tree = etree.HTML(html)

二、selenium的三种等待


1. 强制等待


第一种也是最简单粗暴的一种办法就是强制等待sleep(xx),

from selenium import webdriver
from time import sleep
driver = webdriver.Firefox()
driver.get('https://huilansame.github.io')
sleep(3) # 强制等待3秒再执行下一步
print driver.current_url
driver.quit()

这种叫强制等待,不管你浏览器是否加载完了,程序都得等待3秒,3秒一到,继续执行下面的代码,作为调试很有用,有时候也可以在代码里这样等待,不过不建议总用这种等待方式,太死板,严重影响程序执行速度。


2. 隐性等待


from selenium import webdriver
driver = webdriver.Firefox()
driver.implicitly_wait(30) # 隐性等待,最长等30秒
driver.get('https://huilansame.github.io')
print driver.current_url
driver.quit()

隐形等待是设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截止,然后执行下一步。

注意:这里有一个弊端,那就是程序会一直等待整个页面加载完成,也就是一般情况下你看到浏览器标签栏那个小圈不再转,才会执行下一步,但有时候页面想要的元素早就在加载完成了,但是因为个别js之类的东西特别慢,我仍得等到页面全部完成才能执行下一步,我想等我要的元素出来之后就下一步怎么办?有办法,这就要看selenium提供的另一种等待方式——显性等待wait了。


3. 显性等待

第三种办法就是显性等待,WebDriverWait,配合该类的until()和until_not()方法,就能够根据判断条件而进行灵活地等待了。它主要的意思就是:程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException。
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
#隐性等待和显性等待可以同时用,但要注意:等待的最长时间取两者之中的大者
driver.implicitly_wait(10)

driver.get(‘https://huilansame.github.io’)
locator = (By.LINK_TEXT, ‘CSDN’)
try:
wait = WebDriverWait(driver, 20, 0.5)
wait.until(EC.presence_of_element_located(locator))
print(driver.find_element_by_link_text(‘CSDN’).get_attribute(‘href’))
finally:
driver.close()


4. expected_conditions


expected_conditions是selenium的一个模块,其中包含一系列可用于判断的条件:

EC.title_is
EC.title_contains
这两个条件类验证title,验证传入的参数title是否等于或在driver.title中
EC.presence_of_element_located((By.CSS_SELECTOR,'.ui-page > wrap'))
EC.presence_of_all_elements_located((By.CSS_SELECTOR,'.ui-page'))

这两个条件验证元素是否出现,传入的参数都是元组类型的locator,如(By.ID, ‘kw’)
一个只要一个符合条件的元素加载出来就通过;
另一个必须所有符合条件的元素都加载出来才行

EC.visibility_of_element_located
EC.invisibility_of_element_located
EC.visibility_of

这三个条件验证元素是否可见
前两个传入参数是元组类型的locator,第三个传入WebElement
第一个和第三个其实质是一样的

EC.text_to_be_present_in_element
EC.text_to_be_present_in_element_value

这两个判断某段文本是否出现在某元素中
一个判断元素的text,一个判断元素的value属性

EC.frame_to_be_available_and_switch_to_it

这个条件判断frame是否可切入,
可传入locator元组或者直接传入定位方式:id、name、index或WebElement

#这个条件判断是否有alert出现
EC.alert_is_present
#这个条件判断元素是否可点击,传入locator
EC.element_to_be_clickable
#这四个条件判断元素是否被选中,
第一个条件传入WebElement对象,第二个传入locator元组
#第三个传入WebElement对象以及状态,相等返回True,否则返回False
#第四个传入locator以及状态,相等返回True,否则返回False
EC.element_to_be_selected
EC.element_located_to_be_selected
EC.element_selection_state_to_be
EC.element_located_selection_state_to_be
#最后一个条件判断一个元素是否仍在页面中,传入WebElement对象,可以判断页面是否刷新
EC.staleness_of

三、案例:豆瓣读书,腾讯


案例:豆瓣读书

import json
from urllib import parse
import requests, time
from lxml import etree
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

class Douban:
    def __init__(self,url,kw):
        self.url = url
        self.kw = kw
        self.driver = webdriver.PhantomJS()
        self.info_list = []
        # self.wait = WebDriverWait(self.driver,10)
        self.get_source()


    ## 获取分页的每一页的资源
    def get_source(self):
        ## 分页
        kw = ''
        for i in range(10):
            params = {'search_text':self.kw,
                        'cat': '1001',
                        'start': str(i*15)
                      }
            self.url = self.url + parse.urlencode(params)
            self.driver.get(self.url)
            ## 等待
            time.sleep(3)
            html_str = self.driver.page_source
            self.parse_page(html_str)

    ## 判空
    def get_text(self,text):
        if text:
            return text[0]
        else:
            return ''
    ## 获取所需要的信息资源
    def parse_page(self,content):
        html = etree.HTML(content)
        div_list = html.xpath('.//div[@id="root"]/div/div/div/div/div/div[@class="item-root"]')
        # print(div_list)
        for div in div_list:
            item = {}
            """
            图书名称
            评分
            评价数
            详情页链接
            作者
            出版社
            价格
            出版日期
            """
            ## 图书名称
            name = self.get_text(div.xpath('.//div[@class="title"]/a/text()'))
            ## 评分
            score = self.get_text(div.xpath('.//span[@class="rating_nums"]/text()'))
            ## 评价数
            comment = self.get_text(div.xpath('.//span[@class="pl"]/text()'))
            ## 详情页链接
            detail_url = self.get_text(div.xpath('.//div[@class="title"]/a/@href'))

            ## 价格
            all_info = self.get_text(div.xpath('.//div[@class="meta abstract"]/text()'))
            if all_info:
                info_list = all_info
            else:
                info_list = '"未知"/"未知"/ "未知"/ "未知"'
            info_list = info_list.split('/')
            price = info_list.pop()
            ## 出版日期
            data = info_list.pop()
            ## 出版社
            publish = info_list.pop()
            ## 作者
            author = '/'.join(info_list)

            if all([name, detail_url, author, publish, data, price]):
                item["图书名称"] = name
                item["评分"] = score
                item["评价数"] = comment
                item["详情页链接"] = detail_url
                item["价格"] = price
                item["出版日期"] = data
                item["出版社"] = publish
                item["作者"] = author
            print(item)
            self.info_list.append(item)

if __name__ == '__main__':
    base_url = 'http://book.douban.com/subject_search?'
    db = Douban(base_url,"python")
    with open('douban.json','w',encoding='utf-8') as fp:
        json.dump(db.info_list,fp)

with open('douban.json','r') as fp:
    json.load(fp)

案例:腾讯招聘

import requests,time,re
from lxml import etree
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

from urllib import parse

class Tencent(object):
    def __init__(self,url):
        self.url = url
        self.driver = webdriver.PhantomJS()
        ## 显性等待  有三个参数,第一个为driver对象;第二个为最大等待时间,单位秒;第三个默认0.5秒刷新一次
        self.wait = WebDriverWait(self.driver,10)
        self.parse()

    def get_text(self,text):
        if text:
            return text[0]
        return ''

    def get_content_by_selenium(self,url,xpath):
        self.driver.get(url)
        #等待
        # time.sleep(3)
        #等到什么完成,until方法里面就是一些条件。
        #locator对象是一个元组
        ## 显性等待等待到什么时候
        webelement = self.wait.until(EC.presence_of_element_located((By.XPATH,xpath)))

        return self.driver.page_source

    def parse(self):
        """
        title
       工作简介
       工作地点
       发布时间
       岗位类别
       详情页链接
        """
        html_str = self.get_content_by_selenium(self.url,'//div[@class="correlation-degree"]')
        html = etree.HTML(html_str)
        div_list = html.xpath('.//div[@class="recruit-list"]')
        # print(div_list)
        for div in div_list:
            item={}
            ## 工作名称
            title = self.get_text(div.xpath('.//a[@class="recruit-list-link"]/h4/text()'))
            ## 工作地点
            location = self.get_text(div.xpath('.//p[@class="recruit-tips"]/span[2]/text()'))
            ## 工作简介
            detail = self.get_text(div.xpath('.//p[@class="recruit-text"]/text()')).replace('\n','')
            ## 发布时间
            date= self.get_text(div.xpath('.//p[@class="recruit-tips"]/span[last()]/text()'))
            ## 岗位类别
            job_type = self.get_text(div.xpath('.//p[@class="recruit-tips"]/span[3]/text()'))
            item["工作名称"] = title
            item["工作地点"] = location
            item["工作简介"] = detail
            item["发布时间"] = date
            item["岗位类别"] = job_type
            print(item)

if __name__ == '__main__':
    base_url = 'https://careers.tencent.com/search.html?index=%s'
    for i in range(1,100):
        Tencent(base_url %i)



发布了107 篇原创文章 · 获赞 43 · 访问量 6134

猜你喜欢

转载自blog.csdn.net/langdei/article/details/102887331