TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
最近开心农场非常火,同学用C#模拟鼠标点击操作做了一个小外挂,但是这样做有如下缺点:1、计算机不能做其他事情,2、必须开着浏览器,3、对所有好友点一遍的时间太慢,4、对于开发者来说技术含量低了点,呵呵。 所以我尝试着改进这种实现,我的想法是:不用开启浏览器,直接运行一个应用程序,该程序将自己伪装成一个浏览器,与服务器连接,并发送浇水、除虫等命令。这样,甚至可以使用多线程向服务器发送命令,无需等待服务器返回一个结果之后再发送下一条命令。从而完全避开了上面几个缺点。 这样做首先要做的是分析在执行每一个浇水(及其他)动作的时候,浏览器向服务器发送了什么请求,有哪些参数,每一个参数的含义是什么,还有服务器端的返回值及其意义。分析完之后,就可以使用java模拟浏览器与服务器建立连接并发送类似的请求。(还有一点,在向服务器端发送浇水请求的时候,你需要知道好友的userId,所以首先需要从服务器获取当前用户的所有好友 userId,然后对每一个userId分别进行各种动作)。
代码如下:
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.PrintStream;
- import java.io.PrintWriter;
- import java.net.MalformedURLException;
- import java.net.SocketTimeoutException;
- import java.net.URL;
- import java.net.URLConnection;
- import java.util.Iterator;
- import java.util.Properties;
- import java.util.Scanner;
- import java.util.Set;
- import net.sf.json.JSONArray;
- import net.sf.json.JSONObject;
- /**
- * 人人网开心农场机器人,能够自动获取好友列表,并对每一个好友的所有作物进行除草、除虫、浇水、摘菜等动作。
- * @author without me
- *
- */
- public class Robot
- {
- //三个配置文件
- private static final String FARM_FILE = "f.properties"; // 存储向服务器发送的两个参数
- private static final String OWNER_FILE = "owner_robot.txt"; //存储好友userId列表
- private static final String CON_FILE = "c.properties"; ///存储连接的Header信息
-
- //请求服务器的URL
- private static final String urlStr =
- "http://xn.hf.fminutes.com/api.php?mod=farmlandstatus&act=&farmKey=&farmTime=&inuId=";
- private static final String getFriendUrl =
- "http://xn.hf.fminutes.com/api.php?mod=friend&farmKey=&farmTime=&inuId=";
-
- //POST参数
- private static final String postStr =
- "Referer=http://xn.cache.fminutes.com/images/v3_3/module/Main.swf?
- v=5&Content-type=application/x-www-form-urlencoded&Content-length: 31&ownerId=&place=";
- private static final String getFriPost =
- "Referer=http://xn.cache.fminutes.com/images/v3_3/module/Main.swf?
- v=5&Content-type+application/x-www-form-urlencoded&Content-length=26&fv=1261051588&refresh=true";
-
- private static final int TIME_OUT = 4000; //超时时间 4秒
- //出现IOException时的提示信息
- private static final String IOE_PROPMT = "无法连接至服务器,请检查网络连接,或者服务器地址是否已更改。";
- private static final String[] action = { "clearWeed", "spraying", "water", "scrounge" };
-
- private String[] owner;
- private Properties farmProp = new Properties();
- private Properties connProp = new Properties();
-
- /**
- * 用3个配置文件对当前的Robot进行初始化,
- * 包括:从OWNER_FILE中读取所有好友信息,从 FARM_FILE中读取向服务器发送的两个参数farmKey,farmTime
- * 从CON_FILE中读取连接的Header信息。
- * @throws IOException
- */
- public Robot() throws IOException
- {
- Scanner scan = new Scanner(new FileInputStream(OWNER_FILE));
- owner = new String[scan.nextInt()];
- int index = 0;
- scan.nextLine();
- while (scan.hasNext())
- {
- owner[index++] = scan.nextLine();
- }
- scan.close();
- farmProp.load(new FileInputStream(FARM_FILE));
- connProp.load(new FileInputStream(CON_FILE));
- }
- /**
- * 获取所有当前用户的好友,并将好友ID保存至文件OWNER_FILE
- */
- public void getFriends()
- {
- try
- {
- //新建一个URL连接,连接地址为 url
- String url = getFriendUrl.replaceFirst("", farmProp.getProperty("farmKey"));
- url = url.replaceFirst("", farmProp.getProperty("farmTime"));
- URLConnection con = new URL(url).openConnection();
- con.setConnectTimeout(TIME_OUT);
- con.setDoOutput(true);
-
- //设置该链接的Header,Header的内容由Properties来定义
- setConnHeader(con, connProp);
-
- //在连接中写入Post的内容
- PrintStream printStr = new PrintStream(con.getOutputStream());
- printStr.print(getFriPost);
- printStr.close();
-
- //获取服务器返回内容并解析
- Scanner scan = new Scanner(con.getInputStream());
- StringBuilder fileBuilder = new StringBuilder();
- int cnt = 0;
- while (scan.hasNext())
- {
- String rtnStr = scan.nextLine();
- JSONArray jsonArray = JSONArray.fromObject("[" + rtnStr + "]").getJSONObject(0).getJSONArray("data");
- cnt += jsonArray.size();
- //将服务器返回的所有用户ID 加入fileBuilder中
- for(int i = 0; i < jsonArray.size(); ++ i)
- fileBuilder.append(jsonArray.getJSONObject(i).getString("userId") + "
- ");
- }
- scan.close();
-
- //将所有用户ID写入文件OWNER_FILE
- PrintWriter writer = new PrintWriter(OWNER_FILE);
- writer.write(String.valueOf(cnt) + "
- " + fileBuilder);
- writer.close();
- }
- catch (MalformedURLException e)
- {
- e.printStackTrace();
- }
- catch (IOException e)
- {
- System.out.println(IOE_PROPMT);
- }
- }
- /**
- * 对所有好友的所有地进行4种操作:浇水、除虫等,每一个好友由单独一个线程完成
- */
- public void work()
- {
- //为每一个好友建立一个线程并分别执行操作
- Thread[] thread = new Thread[owner.length];
- for (int k = 0; k < owner.length; ++k)
- {
- thread[k] = new Thread(new RobotThread(owner[k]));
- thread[k].start();
- }
- }
-
- /**
- * 机器人线程的内部类,一个这样的线程针对单独一个好友进行操作
- * @author without me
- *
- */
- class RobotThread implements Runnable
- {
- private String owner;
- public RobotThread(String owner)
- {
- this.owner = owner;
- }
-
- @Override
- public void run()
- {
- for (int j = 0; j < 4; ++j)
- {
- for (int i = 0; i < 18; ++i)
- {
- URLConnection con;
- try
- {
- //新建一个URL连接,连接地址为tmpUrlStr,将所有urlStr中未设置的参数(即)修改为 farmProp中的值
- String tmpUrlStr = urlStr.replaceFirst("", action[j]);
- tmpUrlStr = tmpUrlStr.replaceFirst("", farmProp.getProperty("farmKey"));
- tmpUrlStr = tmpUrlStr.replaceFirst("", farmProp.getProperty("farmTime"));
- URL url = new URL(tmpUrlStr);
- con = url.openConnection();
- con.setConnectTimeout(TIME_OUT);
- //设置连接的 Header
- setConnHeader(con, connProp);
- con.setDoOutput(true);
-
- //在连接中写入Post的内容
- PrintStream printStr = new PrintStream(con.getOutputStream());
- printStr.print(postStr.replace("", owner) + i);
- printStr.close();
-
- //获取服务器返回内容并解析
- Scanner scan = new Scanner(con.getInputStream());
- if (scan.hasNext())
- {
- JSONArray jsonArray = JSONArray.fromObject("[" + scan.nextLine() + "]");
- JSONObject jsonObject = jsonArray.getJSONObject(0);
-
- //将服务器返回的提示(或是错误信息)打印到客户端
- if (jsonObject.has("direction"))
- System.out.println(owner + " : " +jsonObject.getString("direction"));
- else if (jsonObject.has("error"))
- System.out.println(owner + " : " +jsonObject.getString("error"));
- }
- scan.close();
- }
- catch (SocketTimeoutException ste)
- {
- --i; //如果某一操作超时了,返回继续执行该操作
- }
- catch (IOException e)
- {
- System.out.println(IOE_PROPMT);
- }
- }
- }
- }
- }
- /**
- * 设置连接的Header,即设置RequestProperty
- * @param conn 需要设置Header的 URLConnection
- * @param prop Header内容存储的Properties
- */
- private static void setConnHeader(URLConnection conn, Properties prop)
- {
- Set keySet = prop.keySet();
- Iterator iter = keySet.iterator();
- String key;
- //将Porperties中的所有内容都设置到连接的Header中
- while (iter.hasNext())
- {
- key = (String) iter.next();
- conn.setRequestProperty(key, prop.getProperty(key));
- }
- }
-
-
- }
复制代码 其中需要用到3个文件,分别是 1、FARM_FILE:
farmKey=78247873dd911c736d3cb15603571c31
farmTime=1261223397 farmKey=78247873dd911c736d3cb15603571c31
farmTime=1261223397 存储向服务器端发送的两个参数(现在明确知道的是第二个参数:是指农场的全局时间,第一个参数应该是请求服务器的一个密钥,如果密钥错误会阻止操作――一般会返回重新登录的提示,一个密钥的可用时间是有限的,所以要过一个小时左右更新一次 farmKey,但可惜,我还不知道如何用程序自动更新这个密钥) 2、OWNER_FILE:
46
83***909
72***788
26***857
//还有43个好友userId 是所有好友的userId,第一行是好友的数量。 3、CON_FILE: Host=xn.hf.fminutes.com
User-Agent=
Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 (.NET CLR 3.5.30729)
Accept=text/HTML,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language=zh-cn,zh;q=0.5
Accept-Encoding=gzip,deflate
Accept-Charset=GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive=300
Connection=keep-alive
Cookie=__utma=*********.2079770661.1261199924.*********.126122***63.*;
__utmz=38185962.**********.9.9.utmcsr=apps.renren.com|utmccn=(referral)|utmcmd=referral|utmcct
=/happyfarm; xn_sig_inu=b910579fd123cfef2d92f7d36bf9626c; xn_sig_user
=********; xn_sig_session_key=2.1e8b614040cb******5f9395ae413.3600.1261227600-47305639; __utmc
=38185962; __utmb=38185962.1.10.1261223363
是每一个向服务器发送的请求的Header部分,Header部分包括用户的Cookie,通过Cookie服务器识别当前用户是谁,不同的用户该文件内容不一样。在程序中使用setConnectionHeader()方法将每一个请求的Header设置成文件中的内容。如果需要使用这个程序的话,必须用firebug获取到你的Cookie的内容,并修改这个文件。(由于Cookie中包含了我的用户信息,所以我用*屏蔽掉了一些内容) 程序核心的方法有两个:
1、getFriends()用于第一次使用时获取当前用户的好友信息。
2、work()对所有好友的每块地进行浇水等动作。我是对每一个好友都用一个线程单独操作,比如我有46个好友,就会有 46个线程同时请求服务器,这样效率高很多(如果想要更快,可以使用更多线程)。main函数就两行
Robot r = new Robot();
r.work(); 这是第一次之后的调用,第一次应该先调用getFriends(); 程序的含义看注释应该能够明白,如果要使用程序,一定要将 CON_FILE中的Cookie改为你自己的Cookie,其次,FARM_FILE中的farmKey和farmTime可能也需要修改。修改完着两个文件,程序应该是能够执行的。而好友列表文件,调用Robot的getFriends()方法就能够生成。 PS:程序中用到了JSON-lib来解析服务器返回的数据,JSON-lib下载地址:http://sourceforge.net/projects/json-lib/
源码下载:http://file.javaxxz.com/2014/11/5/000342562.zip |
|