最近利用Python做了一个模拟操作的应用,以下主要是写一些心得吧
最开始接触到的都是根据正则表达式来获取所有的元素,这是我自己定义的方法:
## html: 根据url传入request传回要解析的页面
## regex:正则表达式
def parse_findall(html, regex):
pattern = re.compile(regex, re.S)
items = re.findall(pattern, html)
return items
后来,因为有一些网页会对页面做加密,所以我选择的方法是利用selenium来模拟浏览器操作。这里我用到的是Google Chrome浏览器,所以下载了相对应的driver,具体搭建环境的操作就不做赘述。下载地址:http://chromedriver.storage.googleapis.com/index.html
然后我又定义了一个初始化浏览器的方法:
def chrome_driver_init():
chrome_opt = webdriver.ChromeOptions() # 创建浏览器
driver = webdriver.Chrome(options=chrome_opt)
return driver
这样我每次需要进行模拟操作的时候,就可以直接调用该方法来创建一个浏览器的driver。再根据我的需求,定义了一个根据标签和标签上的属性值获取对应属性内容的方法:
## (浏览器driver,xpath定位,定位的标签属性值)
def get_url(driver, xpath, prop):
url = driver.find_element_by_xpath(xpath).get_attribute(prop)
return url
再根据需求,定义了一个类似于上个方法的来获取对应属性全部内容
## (浏览器driver,xpath定位,定位的标签属性值)
def get_all_url(driver, xpath, prop):
_list = driver.find_elements_by_xpath(xpath)
prop_list = []
for i in range(len(_list )):
prop_list.append(_list [i].get_attribute(prop))
return prop_list
这样的定位基本上不会出错,但是我遇到的情况是页面上存在前一个和后一个的按钮。当当前内容只有一条的时候,我选择的网站会把两个div中的style设置成display: none,现在我有两个方案可以解决该问题:
1.传入的xpath加入 “and @style={display: none;}”
我使用的方法 2.使用selenium.webdriver.support库的expected_conditions和selenium.webdriver.common.by库的By来定位
我选择这个方法的原因是因为页面刷新需要时间,而定位的时候直接调用会导致定位不到,用隐式等待是定一个死的时间。所以我选择了selenium.webdriver.support.wait库的WebDriverWait来显式等待页面的刷新:
def is_has_next(driver, _list):
xpath = "//div[@class='next' and @style='display: none;']" ## 找到该div
WebDriverWait(driver, 10).until(expected_conditions.presence_of_all_elements_located((By.XPATH, xpath))) ##(driver, 设置10s响应等待, 0.5s默认请求一次).until(等待所有符合条件的元素都加载)
#两个()是因为最里面的括号是因为传入的是元组而不是单个单个的参数
for i in range(9):
_next = driver.find_element_by_xpath("//div[@class='next' and @style='display: none;']")
if _next:
break ## 不存在下一个时跳出
else:
_next.click()
_list.append(get_url(driver, "//div[@class='***']/img", "src"))
return url_list
此外我还写了两个等待元素加载的方法:
# 按照classname等待
def as_class_name_wait(driver, class_name):
WebDriverWait(driver, 10, 0.5).until(expected_conditions.element_to_be_clickable((By.CLASS_NAME, class_name)))
# 按照xpath等待
def as_xpath_wait(driver, xpath):
WebDriverWait(driver, 10, 0.5).until(expected_conditions.element_to_be_clickable((By.XPATH, xpath)))
这样基本上就可以解决我的问题了