airevent

Пример кода на питоне

Mar 11th, 2013
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.45 KB | None | 0 0
  1. # coding=UTF-8
  2. # базовый класс бота
  3.  
  4. import html, logic, re, sys, time, urllib, urllib2, cookielib
  5. from sets import Set
  6. from pprint import pprint
  7. from FowWS import FowWS
  8. from threading import Thread
  9. from select import select
  10.  
  11.  
  12.  
  13. class Fow:
  14.     title = "Forces of War bot"
  15.     author = "airevent"
  16.     version = "4.1"
  17.     outdated = "Bot is outdated"
  18.    
  19.     settings_path = "./settings.py"
  20.     accounts_path = "./accounts.py"
  21.     cookies_dir = "./cookies"
  22.    
  23.     commands = Set(["heal", "info", "invasion"])
  24.    
  25.     killed = False
  26.     need_eol = False
  27.    
  28.    
  29.    
  30.     def __init__( self ):
  31.         self.notice("Forces of War bot v"+self.version)
  32.        
  33.         self.configure()
  34.         self.load_cookies()
  35.         self.check_settings()
  36.         self.apply_settings()
  37.        
  38.         self.start()
  39.    
  40.     def start( self ):
  41.         self.notice("Executing command: "+self.command)
  42.         getattr(self, "logic_"+self.command)()
  43.    
  44.     # вход в фейсбук
  45.     def login_stage_1( self, acc ):
  46.         self.notice("Login stage 1 (facebook auth)")
  47.        
  48.         self.notice("Loading facebook root")
  49.         self.query(acc, self.settings["facebook_root"])
  50.        
  51.         form = html.get_form_by_action(acc["last_response"], acc["facebook_login_url_regexp"])
  52.        
  53.         if not form: # уже залогинены
  54.             self.notice("Already logged in facebook")
  55.             return
  56.        
  57.         try:
  58.             form["inputs"]["email"] = acc["facebook_email"]
  59.             form["inputs"]["pass"]  = acc["facebook_pass"]
  60.         except Exception as fail:
  61.             self.error(self.outdated + "; facebook auth form parse failed")
  62.        
  63.         self.notice("Sending facebook auth form")
  64.         self.query(acc, form["action"], urllib.urlencode(form["inputs"]))
  65.    
  66.     # вход в приложение
  67.     def login_stage_2( self, acc ):
  68.         self.notice("Login stage 2 (FoW auth)")
  69.        
  70.         self.notice("Loading fow app url")
  71.         self.query(acc, self.settings["fow_login_url"])
  72.        
  73.         form = html.get_form_by_action(acc["last_response"], acc["fow_login_url_regexp"])
  74.        
  75.         if not form:
  76.             self.error(self.outdated + "; fow login form not found")
  77.             return
  78.        
  79.         self.notice("Sending fow auth form stage 1")
  80.         self.query(acc, form["action"], urllib.urlencode(form["inputs"]))
  81.        
  82.         try:
  83.             self.notice("Sending fow auth form stage 2")
  84.             url = re.search("[\"'](http[^\"']+)[\"']", acc["last_response"]).group(1)
  85.             self.query(acc, url)
  86.         except Exception as fail:
  87.             self.error(self.outdated + "; " + str(fail))
  88.    
  89.     # мы ещё залогинены?
  90.     def in_fow( self, acc ):
  91.         return re.search(acc["fow_session_check"], acc["last_response"])
  92.    
  93.     # авторизация вплоть до главной страницы игры
  94.     def login( self, acc ):
  95.         self.login_stage_1(acc)
  96.         self.login_stage_2(acc)
  97.         self.save_cookies(acc)
  98.    
  99.     # собрать игровую инфу о персонаже
  100.     def gather_info( self, acc ):
  101.         self.notice("Gathering info")
  102.         self.game_query(acc, acc["fow_root"])
  103.         logic.parse_main_info(acc)
  104.    
  105.     # результат удара босса
  106.     def check_boss_answer( self, acc, boss ):
  107.         flags = re.IGNORECASE | re.MULTILINE | re.DOTALL
  108.        
  109.         r = re.search("you are too high a level to fight", acc["last_response"], flags=flags)
  110.         if r: return "highlvl"
  111.        
  112.         r = re.search("you aren.*? strong enough to fight", acc["last_response"], flags=flags)
  113.         if r: return "lowlvl"
  114.        
  115.         r = re.search("is already dead!", acc["last_response"], flags=flags)
  116.         if r: return "dead"
  117.        
  118.         r = re.search("must wait at least 1 second between", acc["last_response"], flags=flags)
  119.         if r: return "1second"
  120.        
  121.         r = re.search("have any stamina to engage in battle", acc["last_response"], flags=flags)
  122.         if r: return "noammo"
  123.        
  124.         r = re.search("too weak to battle. You must wait until your health", acc["last_response"], flags=flags)
  125.         if r: return "nohp"
  126.    
  127.     # ударить босса
  128.     def hit_boss( self, acc, boss ):
  129.         flags = re.IGNORECASE | re.MULTILINE | re.DOTALL
  130.         npc_id = boss["id"]
  131.        
  132.         self.notice("hitting boss " + str(npc_id) + " by " + acc["accname"])
  133.        
  134.         self.game_query(acc, acc["fow_root"]+"npc/attack", urllib.urlencode({
  135.             "utf8": "&#x2713",
  136.             "authenticity_token": acc["info"]["csrf-token"],
  137.             "npc_id": npc_id,
  138.             "commit": "ATTACK",
  139.         }), True)
  140.        
  141.         info = re.search("&nbsp; ([\-0-9]+).n\s+<[^>]+span>health.*?&nbsp; ([\-0-9]+).n\s+<[^>]+span>dmg", acc["last_response"], flags=flags)
  142.        
  143.         if not info:
  144.             status = self.check_boss_answer(acc, boss)
  145.             if status=="highlvl":
  146.                 self.notice("boss lvl is too low")
  147.                 boss["bad"] = True
  148.             elif status=="lowlvl":
  149.                 self.notice(acc["accname"] + " is too low for this boss")
  150.                 boss["bad"] = True
  151.             elif status=="dead":
  152.                 self.notice("boss dead")
  153.                 boss["bad"] = True
  154.             elif status=="1second":
  155.                 self.notice("1 second attack limit triggered, oops")
  156.             elif status=="noammo":
  157.                 self.notice("no ammo, waiting for 5 minutes")
  158.                 time.sleep(5*60)
  159.             elif status=="nohp":
  160.                 self.notice("no health")
  161.                 self.fow.heal(acc, "full")
  162.                 return self.hit_boss(acc, boss)
  163.             else:
  164.                 pass
  165.         else:
  166.             lost = int(info.group(1))
  167.             dealt = int(info.group(2))
  168.             boss["lost"] += lost
  169.             boss["dealt"] += dealt
  170.            
  171.             self.notice("hit result: " + str(lost) + " lost; " + str(dealt) + " dealt")
  172.            
  173.             return self.hit_boss(acc, boss)
  174.    
  175.     # загрузить инфу о боссе (уровень, возможность ударить)
  176.     def load_boss_info( self, acc, npc_id ):
  177.         flags = re.IGNORECASE | re.MULTILINE | re.DOTALL
  178.        
  179.         self.notice("getting boss " + str(npc_id) + " info")
  180.        
  181.         self.game_query(acc, acc["fow_root"]+"villains")
  182.        
  183.         tr = re.search("<tr npc=."+str(npc_id)+".>(.*?)</tr>", acc["last_response"], flags=flags)
  184.        
  185.         if not tr: return None
  186.        
  187.         tr = tr.group(1)
  188.        
  189.         # если нет кнопки атаки, то level не нужен
  190.         level = re.search(">\s*Level\s*([0-9]+)\s*<.*?<input.*?type=\"submit\"", tr, flags=flags)
  191.        
  192.         if not level: return None
  193.        
  194.         return {
  195.             "level": int(level.group(1)),
  196.         }
  197.    
  198.     # напечатать игровую инфу
  199.     def logic_info( self ):
  200.         acc = self.accounts[self.account]
  201.         self.gather_info(acc)
  202.        
  203.         pprint(acc["info"])
  204.    
  205.     # вылечиться
  206.     def heal( self, acc, full=False ):
  207.         url = acc["fow_root"] + "regeneration_chamber/regenerate"
  208.        
  209.         if full:
  210.             self.notice("healing for full hp")
  211.             url += "?type=full"
  212.         else:
  213.             self.notice("healing for 15%")
  214.        
  215.         self.game_query(acc, url, urllib.urlencode({
  216.             "utf8": "&#x2713",
  217.             "authenticity_token": acc["info"]["csrf-token"],
  218.             "commit": "heal",
  219.         }), True)
  220.    
  221.     # лечиться
  222.     def logic_heal( self ):
  223.         acc = self.accounts[self.account]
  224.        
  225.         self.gather_info(acc)
  226.        
  227.         self.start_exit_thread()
  228.        
  229.         acc["ws"] = FowWS(acc)
  230.         acc["ws"].start()
  231.    
  232.     # добывать золотые слитки
  233.     def logic_invasion( self ):
  234.         acc = self.accounts[self.account]
  235.        
  236.         self.notice(acc["accname"] + " hp_percent_to_start_hit_boss = " + str(acc["hp_percent_to_start_hit_boss"]))
  237.        
  238.         self.gather_info(acc)
  239.        
  240.         self.start_exit_thread()
  241.        
  242.         acc["ws"] = FowWS(acc)
  243.         acc["ws"].start()
  244.    
  245.     # начать ожидание ввода команды выхода в отд. потоке
  246.     def start_exit_thread( self ):
  247.         thread = Thread(target = self.wait_for_stop)
  248.         thread.start()
  249.    
  250.     def wait_for_stop( self ):
  251.         while 1:
  252.             if self.killed: break
  253.            
  254.             cmd = raw_input()
  255.            
  256.             if cmd=="stop" or cmd=="exit" or cmd=="quit":
  257.                 self.killed = True
  258.    
  259.     # чтение настроек
  260.     def configure( self ):
  261.         try:
  262.             exec(open(self.settings_path).read())
  263.             exec(open(self.accounts_path).read())
  264.         except Exception as fail:
  265.             self.error("File import failed: " + str(fail))
  266.        
  267.         try:
  268.             self.command = sys.argv[1]
  269.         except Exception as fail:
  270.             self.error("Command not specified")
  271.        
  272.         try:
  273.             self.account = sys.argv[2]
  274.         except Exception as fail:
  275.             self.error("Account not specified")
  276.    
  277.     # проверка настроек
  278.     def check_settings( self ):
  279.         if not self.command in self.commands:
  280.             self.error("Unknown command: "+self.command)
  281.        
  282.         if not self.account in self.accounts:
  283.             self.error("Unknown account: "+self.account)
  284.    
  285.     # скопировать дефолтные настройки каждому акку
  286.     def apply_settings( self ):
  287.         for accname in self.accounts:
  288.             if accname=="example": continue
  289.            
  290.             acc = self.accounts[accname]
  291.            
  292.             for name in self.settings:
  293.                 if not name in acc: acc[name] = self.settings[name]
  294.    
  295.     # сохранить куки на диск выбранного акка
  296.     def save_cookies( self, acc ):
  297.         cj = acc["cookies"]
  298.         cookies_path = acc["cookies_path"]
  299.        
  300.         try:
  301.             cj.save(cookies_path, True, True)
  302.         except Exception as fail:
  303.             self.error("Unable to write cookies to file " + cookies_path + "; " + str(fail))
  304.    
  305.     # запрос с проверкой на игровую сессию
  306.     def game_query( self, acc, url, data=None, ajax=False ):
  307.         self.query(acc, url, data, ajax)
  308.        
  309.         if not ajax and not self.in_fow(acc):
  310.             self.notice("Session lost, re-logging")
  311.             self.login(acc)
  312.             return self.game_query(acc, url, data, ajax)
  313.    
  314.     # запрос без проверки на сессию
  315.     def query( self, acc, url, data=None, ajax=False ):
  316.         headers = {
  317.             "User-Agent": self.settings["User-Agent"],
  318.             "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  319.             "Accept-Charset": "windows-1251,utf-8;q=0.7,*;q=0.3",
  320.             "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4",
  321.         }
  322.        
  323.         if "info" in acc and "uken-sesh" in acc["info"]:
  324.             if re.search("\?", url): url += "&"
  325.             else: url += "?"
  326.             url += "u_vln="+acc["info"]["uken-sesh"]
  327.        
  328.         if ajax:
  329.             headers["Accept"] = "text/javascript, application/javascript, */*"
  330.             headers["X-Requested-With"] = "XMLHttpRequest"
  331.             headers["X-CSRF-Token"] = acc["info"]["csrf-token"]
  332.             headers["Origin"] = acc["fow_root"]
  333.             headers["Referer"] = acc["fow_root"]
  334.        
  335.         request = urllib2.Request(url, data, headers)
  336.        
  337.         try:
  338.             r = acc["browser"].open(request)
  339.             acc["last_response"] = r.read()
  340.         except Exception as fail:
  341.             self.notice("Query failed, retrying in 5 seconds; " + str(fail))
  342.             time.sleep(acc["retry_query_pause"])
  343.            
  344.             if self.fow.killed:
  345.                 self.fow.error("stopped by user input")
  346.            
  347.             return self.query(acc, url, data, ajax) # must be tail recursion
  348.        
  349.     # загрузить куки всех акков, если файла нет - создать пустые
  350.     def load_cookies( self ):
  351.         for accname in self.accounts:
  352.             if accname=="example": continue
  353.            
  354.             acc = self.accounts[accname]
  355.             cj = cookielib.MozillaCookieJar()
  356.             cookies_path = self.cookies_dir+"/"+accname+".cookie"
  357.            
  358.             try:
  359.                 cj.load(cookies_path, True, True)
  360.             except:
  361.                 pass
  362.            
  363.             acc["cookies_path"] = cookies_path
  364.             acc["cookies"] = cj
  365.            
  366.             cp = urllib2.HTTPCookieProcessor(cj)
  367.            
  368.             if "proxy" in acc:
  369.                 self.notice(accname + " will use proxy-server: "+str(acc["proxy"]))
  370.                 ph = urllib2.ProxyHandler(acc["proxy"])
  371.             else:
  372.                 ph = urllib2.ProxyHandler(None)
  373.            
  374.             acc["browser"] = urllib2.build_opener(cp, ph)
  375.             acc["accname"] = accname
  376.             acc["last_response"] = ""
  377.             acc["fow"] = self
  378.             acc["info"] = {}
  379.    
  380.     def add_eol_if_need( self ):
  381.         if self.need_eol:
  382.             print("")
  383.             self.need_eol = False
  384.    
  385.     def notice( self, msg ):
  386.         self.add_eol_if_need()
  387.         print(time.strftime("%H:%M:%S    ") + str(msg))
  388.         self.need_eol = False
  389.         sys.stdout.flush()
  390.    
  391.     def error( self, msg ):
  392.         self.add_eol_if_need()
  393.         self.notice("Fatal error: " + str(msg))
  394.         self.need_eol = False
  395.         self.killed = True
  396.         sys.exit(1)
Advertisement
Add Comment
Please, Sign In to add comment