Python模拟浏览器实现用户响应

最近工作中遇到一个问题,在集群上运行的任务有时候无法正常结束,或者无法正常启动。这会造成这批运行的任务无法正常结束运行,处于pending的状态,导致后面的任务无法正常启动。

该问题困扰我们项目已经有半年左右了,一直没有想到很好的解决办法。主要原因就是任务的状态只能在浏览器中看出,无法通过后台的日志或者数据库查询得到。在浏览器中,如果我们看到某个任务长时间没有运行时间和状态的变化,就可以把这个任务当做是“僵尸”任务,从而可以将该任务手动结束掉(kill)。

春节之后在网上看到一些有关爬虫的文章,里面提到过有一种爬虫就是模拟浏览器的行为(包括登录、点击等)去得到网页的数据,进而进行网页抓取,有用信息提取。于是我思考,我们项目的问题和浏览器的交互,只有几种情况,完全可以通过这种方式解决“僵尸”任务。经过一周左右的研究和一周断断续续的coding,终于将这个问题解决了,现在把解决问题的主要思路和关键技术难点写下来,希望一来可以加深自己的印象,二来可以帮助到需要的人。因为实现的任务比较单一,且实现过程比较仓促,code主要就是实现了一些功能,没有进行优化,也没有太参考什么编码规范,设计模式之类的。以后遇到更大的问题,再考虑这些吧。

技术要点:

(1)Python的package:selenium,用这个package,可以和浏览器进行交互,如打开某个浏览器(Chrome,FireFox等),登录需要验证的网站(输入用户名&密码),点击某个特定图标等等,下面是两个有关selenium的链接:

https://www.baidu.com/link?url=tTeJRPOMKX8noXyTa2YPgpaD6vVlGQ2-RVAfwRg4Yvm&wd=&eqid=acd0879a0043c2e9000000045741cd39

http://www.cnblogs.com/fnng/archive/2013/05/29/3106515.html

(2)seleniumPhantomJS,这是一个虚拟的浏览器,可以把它看成一个在后台运行的浏览器,用户看不到浏览器的页面,但其他的功能和普通浏览器基本一样,比如可以截图,点击某个图标,抓取网页信息等,之所以使用了这个用来模仿浏览器,是因为我们的server无法安装普通的浏览器,只能运行在终端模式下运行的程序;

http://phantomjs.org/

(3)xpath,这个是我编程中耗时最多的模块,主要原因有几个,一是元素定位有问题,网站是一秒钟刷新一次,上一秒获取到的元素下一秒就找不到了;二是相似元素太多,层级关系太复杂,用一般的相对路径去寻找,有可能找到一些不想要的元素,所以就造成了寻找元素过程的费时费力。下面是两个有关xpath的介绍,比较实用,特别是在网页爬虫方面(后面我还要专门介绍爬虫):

http://www.cnblogs.com/fdszlzl/archive/2009/06/02/1494836.html

http://www.ruanyifeng.com/blog/2009/07/xpath_path_expressions.html

以下是核心code,因为项目隐私的原因,把一些敏感的内容用*******代替。如果有什么问题,可以给我留言。

‘‘‘
command: 

python tools/webScrap/KillJobs.py -url=******** -screenShotPath=******

‘‘‘

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.keys import Keys
import re
import time
import argparse
import sys
import os

mailReceiver = [
                    *********,
                    ********
                ]

ZOMBIE_JOB_LIST = {"list1": [], "list2": [], "list3":[]}

def getMailReceiver():
    receiver = ‘ ‘
    for recv in mailReceiver:
        receiver = receiver + recv + ‘ ‘

    return receiver

def kill_zombie_jobs(screenShotPath, url):
    # browser = webdriver.PhantomJS() # Get local session of PhantomJS
    browser = webdriver.Firefox() # Get local session of Firefox
    browser.set_window_size(1600, 1000)

    targetUrl = "http://%s/#JOBS" %url
    print "url: ", targetUrl

    job_to_be_kill_indicate = 0

    browser.get(targetUrl) # Load page
    userName = browser.find_elements_by_class_name("gwt-TextBox")
    password = browser.find_elements_by_class_name("gwt-PasswordTextBox")
    submitButton = browser.find_elements_by_class_name("gwt-Button")

    if len(userName) == 0 or len(password) == 0 or len(submitButton) == 0:
        print "error in open url: %s" %targetUrl
        browser.quit()
        return

    userName[0].send_keys("******")
    password[0].send_keys("*******")
    time.sleep(1)
    submitButton[0].click()

    time.sleep(4)

    sceen_shot_name = screenShotPath + "/Before_kill_jobs_screen_shot.png"
    browser.save_screenshot(sceen_shot_name)

    # get the Job_Name
    # job_name_pattern = "/html/body/div[2]/div[2]/div/div[4]/div/div[3]/div/div[4]/div/div[2]/div/div[2]/div/div/div/div[3]/table[2]/tbody/tr[1]/td/fieldset/table/tbody/tr/td/table/tbody/tr[1]/td/table/tbody[1]/tr[1]/td[1]/div"
    # jobs_name_pattern_0 = "//body/div[2]/div[2]/div/div[4]/div/div[3]/div/div[4]/div/div[2]/div/div[2]/div/div/div/div[3]/table[2]/tbody/tr[1]/td/fieldset/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td[@class=‘GJOFO-MDOC GJOFO-MDAD GJOFO-MDBD‘ or @class=‘GJOFO-MDOC GJOFO-MDAE GJOFO-MDBD‘]"
    jobs_name_pattern_0 = "//body/div[2]/div[2]/div/div[4]/div/div[3]/div/div[4]/div/div[2]/div/div[2]/div/div/div/div[3]/table[2]/tbody/tr[1]/td/fieldset/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td[1]"
    jobs_name_pattern = "//body/div[2]/div[2]/div/div[4]/div/div[3]/div/div[4]/div/div[2]/div/div[2]/div/div/div/div[3]/table[2]/tbody/tr[1]/td/fieldset/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[Order]/td[1]"
    jobs_kill_pattern = "//body/div[2]/div[2]/div/div[4]/div/div[3]/div/div[4]/div/div[2]/div/div[2]/div/div/div/div[3]/table[2]/tbody/tr[1]/td/fieldset/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[Order]/td[3]"
    jobs_duration_pattern = "//body/div[2]/div[2]/div/div[4]/div/div[3]/div/div[4]/div/div[2]/div/div[2]/div/div/div/div[3]/table[2]/tbody/tr[1]/td/fieldset/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[Order]/td[5]"

    for i in range(1, 4):
        tmp_list = "list"+str(i)
        job_name_elements_list = browser.find_elements_by_xpath(jobs_name_pattern_0)
        job_length = len(job_name_elements_list) 

        for index in range(1, job_length+1):
            job_name_pattern = jobs_name_pattern.replace("Order", str(index))
            job_duration_pattern = jobs_duration_pattern.replace("Order", str(index))

            job_name = get_element_name(browser, job_name_pattern)
            job_duration_time = durationTime(get_element_name(browser, job_duration_pattern))

            if len(job_name) > 10 and durationTime == 0:
                ZOMBIE_JOB_LIST[tmp_list].append(job_name)
        time.sleep(60)

    print "zombie job list: ", ZOMBIE_JOB_LIST

    job_name_elements_list = browser.find_elements_by_xpath(jobs_name_pattern_0)
    job_length = len(job_name_elements_list)
    for index in range(1, job_length+1):
        # print "index:", index
        job_name_pattern = jobs_name_pattern.replace("Order", str(index))
        job_kill_pattern = jobs_kill_pattern.replace("Order", str(index))
        job_name = get_element_name(browser, job_name_pattern)

        if job_name in ZOMBIE_JOB_LIST["list1"] and job_name in ZOMBIE_JOB_LIST["list2"] and  job_name in ZOMBIE_JOB_LIST["list3"]:
            job_to_be_kill_indicate = 1
            print "this job is should be killed: ", job_name
            kill_button_element = browser.find_element_by_xpath(job_kill_pattern)
            kill_button_element.click()
            time.sleep(1)
            confirm_kill_button_pattern = "//tbody/tr/td[1]/button[@class=‘gwt-Button‘]"
            confirm_kill_button_element = browser.find_element_by_xpath(confirm_kill_button_pattern)
            confirm_kill_button_element.click()
            time.sleep(2)

    time.sleep(2)
    sceen_shot_name = screenShotPath + "/After_kill_jobs_screen_shot.png"
    browser.save_screenshot(sceen_shot_name)
    browser.quit()
    return job_to_be_kill_indicate

def get_element_name(browser, element_pattern):
    element_name = ""
    try:
        element = browser.find_element_by_xpath(element_pattern)
        element_name = element.text
    except Exception, e:
        print "element not exist any more!!!!!"
        element_name = ""

    return element_name

def durationTime(timeStr):
    if timeStr is None or timeStr == "":
        return 0
    if re.match(r"\d{2}:\d{2}:\d{2}", timeStr) is None:
        return 0

    timeSec = int(timeStr[0:2]) * 3600 + int(timeStr[3:5]) * 60 + int(timeStr[6:8])

    return timeSec

def send_kill_jobs_mail(mailer, screenShotPath, url, indicator):
    # jobs screen before and after kill
    mailTitle = "Jobs_on_%s_Hanging"  %url
    screenShotFile1 = screenShotPath + "/Before_kill_jobs_screen_shot.png"
    screenShotFile2 = screenShotPath + "/After_kill_jobs_screen_shot.png"
    logFile = screenShotPath + "/nodes_hanging.log"
    command = ‘mail -a ‘ + screenShotFile1 + ‘ -a ‘ + screenShotFile2 + ‘ -s ‘ + mailTitle + mailer +  ‘ < ‘ + logFile
    print "command: ", command
    os.system(command)

    return 0

def monitor():
    # kill exist PhantomJS
    command = "killall phantomjs"
    print "kill all existing phantomjs: ", command
    os.system(command)

    parser = argparse.ArgumentParser()
    parser.add_argument(‘-url‘, action=‘store‘, dest=‘url‘, help=‘data url‘, required=True)
    parser.add_argument(‘-screenShotPath‘, action=‘store‘, dest=‘screenShotPath‘, help=‘the screen shot path‘, required=True)
    results = parser.parse_args()

    print ‘DataRush URL = ‘, results.url
    url = results.url
    print ‘Screen Shot Path  = ‘, results.screenShotPath
    screenShotPath = results.screenShotPath

    mailer = getMailReceiver()

    print "START: Monitor DataRush Starting.............................." 

    job_killed_inicate = kill_zombie_jobs(screenShotPath, url)

    if job_killed_inicate == 1:
        print "zombie jobs has been killed!!!!!!!"
        send_kill_jobs_mail(mailer, screenShotPath, url, 1)
    else:
        pass

    print "End: Monitor Finished....................................." 

if __name__ == ‘__main__‘:
    monitor()

  

时间: 2024-08-24 20:16:07

Python模拟浏览器实现用户响应的相关文章

记:使用python模拟浏览器发送http消息

python自带的urllib,urllib2可以极方便做http操作,在我们按照http方式提交消息请求后,有可能会看见返回这个错误“403 forbidden",这是请求的网站做了阻止,于是我们需要把自己伪装成模拟器.对此,可以加上headers={'User-Agent':user-agent,'cookie':cookie},注意操作的网站 需要登录账号的话,就需要加上cookie,这两个值可以通过chrome的”开发者工具“查看: 把他们加上去,然后在请求值那里再加上: req = u

Python模拟浏览器实现网页访问

模拟浏览器请求数据: import socket # 创建TCP链接 tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # DNS 解析和链接HTTP服务器 tcp_socket.connect(("www.qq.com", 80)) # 编写请求头, 发送HTTP请求报文 # 请求行 request_line = "GET / HTTP/1.1\r\n" # 请求头,设置请求域名 requ

python模拟浏览器登陆

#! /usr/bin/env python # -*-coding:utf-8 -*- import urllib import urllib2 import cookielib class NetRobot: def __init__(self, baseurl): self.cj = cookielib.CookieJar() self.baseurl = baseurl self.opener = urllib2.build_opener(urllib2.HTTPCookieProces

python模拟浏览器登陆人人网站

想要实现网站的登陆,post方法就是提交数据到网站,所以要post数据来用python实现登陆.当你想要登陆人人时,首先要知道网站的登陆细节(先发送账号和密码,返回cookie值,发送cookie到服务器,返回页面,再使用正则提取你想要的数据),我是通过HTTPfox来抓取http数据包来分析这个网站的登陆流程.同时,我们还要分析抓到的post包的数据结构和header,要根据提交的数据结构和heander来构造自己的post数据和header. 分析结束后,我们要构造自己的HTTP数据包,并发

python模拟浏览器登陆淘宝(设置代理、输入验证码)

终于实现了登陆淘宝,这个验证码机制困惑了我好几天啊. 代码中验证码提供有两种方式,第一种通过webbrowser的open直接在浏览器中打开含有验证码的图片,第二种就是将其以jepg格式存在 C:\\Users\\Administrator\\Desktop\\checkcode.jepg.你可以根据自己主机的用户名更改路径.同时这个代码必须先指定用户名和账号也 可以实时输入账号的密码,小小修改一下代码就可以. 显示根据httpfox分析网页数据,之后再使用正则扣除你想要的数据,将其显示出来.过

python:爬虫1——实战(下载一张图片、用Python模拟浏览器,通过在线的有道词典来对文本翻译)

一.下载一只猫 import urllib.request response = urllib.request.urlopen("http://cdn.duitang.com/uploads/item/201111/24/20111124222137_wHYwc.jpg") cat_img = response.read() with open('cat_0.jpeg', 'wb') as f: f.write(cat_img) urlopen()中的url可以是string,也可以是

爬虫-使用模拟浏览器操作(截取网页)

最近遇到一个问题就是,如何模拟真实浏览器行为然后截取显示的网页. 方案 模拟登陆网站或者直接使用cookie登陆. 对指定页面按钮进行点击刷新页面,截取网页. 我们使用selenium库来操作浏览器驱动,即执行浏览器相应的驱动命令,实现相应的浏览器操作. 准备工作 selenium库 浏览器自动化测试框架,其作用是通过操作浏览器驱动来控制浏览器行为,达到模拟真实用户操作浏览器的效果.原理为自动化测试python脚本-->浏览器driver -->浏览器.官网 python中文文档 python

splinter python浏览器自动化操作,模拟浏览器的行为

Splinter可以非常棒的模拟浏览器的行为,Splinter提供了丰富的API,可以获取页面的信息判断当前的行为所产生的结果 最近在研究网站自动登录的问题,涉及到需要实现浏览器自动化操作,网上有不少介绍,例如使用pamie,但是只是支持IE,而且项目也较久没有更新了.还 有就是利用selenium,可支持多种浏览器.网上资料比较多.经过比较,我选择了Splinter模块,因为利用Splinter开发浏览器自动化操 作,编写代码比较简单. 一.Splinter的安装 Splinter的使用必修依

浅析HTTP中POST和GET区别并用Python模拟其响应和请求

最近在几周在做手游崩溃信息收集和上传,拿到崩溃信息后,使用的是HTTP的POST方法上传到公司共用的服务器的,因此做简单总结.本文首先简单介绍了HTTP协议,主要说明了POST方法和GET方法的区别:然后用Python实现了 对POST方法和GET方法的响应:最后用Python模拟了POST方法和GET方法的请求. HTTP协议简介 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写,简单来说它是一个应用层的协议,它允许将超文本标记语言(HTML)文档从W