Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public final class GenieSearcher {
- private String username;
- private String password;
- private String useragent;
- private String loginFormUrl;
- private String loginUrl;
- private String changeAreaSettingsUrl;
- private String changeZipSettingsUrl;
- private String changeSicSettingsUrl;
- private String dataSearchUrl;
- private String sessionId;
- private String[] lastSentCounties = new String[0];
- private String[] lastSentStates = new String[0];
- private String[] lastSentZips = new String[0];
- private String[] lastSentSics = new String[0];
- private CloseableHttpClient client = null;
- private final List<Callback<SearchEntry>> parseCallbacks = new ArrayList<Callback<SearchEntry>>();
- private boolean running = true;
- private int cachedRecordCount = 0;
- /**
- * @param username
- * @param password
- * @param useragent
- */
- public GenieSearcher(String username, String password) {
- this.username = username;
- this.password = password;
- try {
- reset();
- parseConfig();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * Parses all external configuration data related to this bot.
- *
- * @throws IOException
- */
- private void parseConfig() throws IOException {
- Map<String, String> kv = ConfigurationParser.parse(new File("./data/bot.cfg"));
- this.loginFormUrl = kv.get("login_form_url");
- this.loginUrl = kv.get("login_url");
- this.changeAreaSettingsUrl = kv.get("change_area_settings_url");
- this.changeZipSettingsUrl = kv.get("change_zip_settings_url");
- this.changeSicSettingsUrl = kv.get("change_sic_settings_url");
- this.dataSearchUrl = kv.get("data_search_url");
- this.useragent = kv.get("user_agent");
- }
- /**
- * Resets all state currently held by this bot.
- *
- * @throws Exception
- */
- private void reset() throws Exception {
- if (client != null) {
- client.close();
- }
- SSLContextBuilder builder = new SSLContextBuilder();
- builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
- SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
- client = HttpClients.custom().
- setUserAgent(useragent).
- setSSLSocketFactory(sslsf).build();
- }
- /**
- * Attempts to login using the user name and password provided during initialization, and
- * then proceeds to attempt to pass the static authentication page redirected to by the web server.
- *
- * @throws IOException
- */
- public void login() throws IOException {
- HttpGet get = new HttpGet(loginFormUrl);
- appendFakeHeaders(get);
- CloseableHttpResponse loginFormResponse = client.execute(get);
- Document document = Jsoup.parse(HttpClientUtil.textual(loginFormResponse.getEntity()));
- String token = document.select("input[name=__RequestVerificationToken]").first().attr("value");
- String signinUrl = document.getElementById("OriginalSigninUrl").attr("value");
- String returnUrl = document.getElementById("ReturnUrl").attr("value");
- String wa = document.getElementById("Wa").attr("value");
- String wct = document.getElementById("Wct").attr("value");
- String wctx = document.getElementById("Wctx").attr("value");
- String wtrealm = document.getElementById("Wtrealm").attr("value");
- HttpPost post = new HttpPost(loginUrl);
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("UserName", username));
- params.add(new BasicNameValuePair("Password", password));
- params.add(new BasicNameValuePair("__RequestVerificationToken", token));
- params.add(new BasicNameValuePair("EnableSSO", "False"));
- params.add(new BasicNameValuePair("OriginalSigninUrl", signinUrl));
- params.add(new BasicNameValuePair("RememberHRDSelection", "True"));
- params.add(new BasicNameValuePair("ReturnUrl", returnUrl));
- params.add(new BasicNameValuePair("Wa", wa));
- params.add(new BasicNameValuePair("Wct", wct));
- params.add(new BasicNameValuePair("Wctx", wctx));
- params.add(new BasicNameValuePair("Wtrealm", wtrealm));
- params.add(new BasicNameValuePair("formSignIn", ""));
- post.setEntity(new UrlEncodedFormEntity(params));
- appendFakeHeaders(post);
- CloseableHttpResponse loginResponse = client.execute(post);
- if (loginResponse.getStatusLine().getStatusCode() != 302) {
- throw new IOException("Login page failed to redirect!");
- }
- document = Jsoup.parse(HttpClientUtil.textual(loginResponse.getEntity()));
- // After successfully logging in, any attempt to access another page will result in a static
- // authentication page one time; we'll go through that here.
- String localRedirectUrl = loginResponse.getHeaders("Location")[0].getValue();
- handleAuthPage(localRedirectUrl);
- retrieveSessionId();
- }
- /**
- * Navigates through the authentication page at the provided (local) URL.
- *
- * @param localUrl
- * @throws IOException
- */
- private void handleAuthPage(String localUrl) throws IOException {
- HttpGet get = new HttpGet("https://auth.salesgenie.com" + localUrl);
- appendFakeHeaders(get);
- CloseableHttpResponse authResponse = client.execute(get);
- Document document = Jsoup.parse(HttpClientUtil.textual(authResponse));
- String wa = document.select("input[name=wa]").attr("value");
- String wresult = document.select("input[name=wresult]").attr("value");
- String wctx = document.select("input[name=wctx]").attr("value");
- HttpPost post = new HttpPost("https://app.salesgenie.com/Home/Home");
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("wa", wa));
- params.add(new BasicNameValuePair("wresult", wresult));
- params.add(new BasicNameValuePair("wctx", wctx));
- post.setEntity(new UrlEncodedFormEntity(params));
- appendFakeHeaders(post);
- client.execute(post);
- }
- /**
- * Retrieves the currently in use session id from the build list page.
- *
- * @throws IOException
- */
- public void retrieveSessionId() throws IOException {
- // https://app.salesgenie.com/UsBusiness/ResultView/
- String url = "https://app.salesgenie.com/UsBusiness/ResultView/"; //https://app.salesgenie.com/UsBusiness/Search/Quick?
- HttpPost post = new HttpPost(url);
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("businessName", ""));
- params.add(new BasicNameValuePair("executiveFirstName", ""));
- params.add(new BasicNameValuePair("rangeStreetNumber", ""));
- params.add(new BasicNameValuePair("rangeStreetCity", ""));
- params.add(new BasicNameValuePair("rangeStreetZip", ""));
- params.add(new BasicNameValuePair("phone", ""));
- params.add(new BasicNameValuePair("executiveLastName", ""));
- params.add(new BasicNameValuePair("rangeStreetName", ""));
- params.add(new BasicNameValuePair("rangeStreetState", "VA"));
- post.setEntity(new UrlEncodedFormEntity(params));
- appendFakeHeaders(post);
- CloseableHttpResponse response = client.execute(post);
- Document document = Jsoup.parse(HttpClientUtil.textual(response));
- System.out.println(document.text());
- String textual = document.text();
- JSONObject obj = new JSONObject(textual);
- sessionId = obj.getJSONObject("data").getString("RequestKey");
- this.sendAreaSettings(new String[0], new String[0]);
- }
- /**
- * Updates the area settings the web server will use to conduct data searches.
- *
- * @param counties
- * @param states
- * @throws IOException
- */
- public void sendAreaSettings(String[] counties, String[] states) throws IOException {
- this.lastSentCounties = counties;
- this.lastSentStates = states;
- StringBuilder countyParamBuilder = new StringBuilder();
- if (counties.length > 0) {
- for (String s : counties) {
- countyParamBuilder.append(s).append(",");
- }
- countyParamBuilder.setLength(countyParamBuilder.length() - 1);
- }
- StringBuilder stateParamBuilder = new StringBuilder();
- if (states.length > 0) {
- for (String s : states) {
- stateParamBuilder.append(s).append(",");
- }
- stateParamBuilder.setLength(stateParamBuilder.length() - 1);
- }
- HttpPost post = new HttpPost(changeAreaSettingsUrl + sessionId);
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("cities", ""));
- params.add(new BasicNameValuePair("counties", countyParamBuilder.toString()));
- params.add(new BasicNameValuePair("states", stateParamBuilder.toString()));
- params.add(new BasicNameValuePair("microAreas", ""));
- params.add(new BasicNameValuePair("metroAreas", ""));
- params.add(new BasicNameValuePair("commit", "true"));
- post.setEntity(new UrlEncodedFormEntity(params));
- appendFakeHeaders(post);
- CloseableHttpResponse response = client.execute(post);
- String textual = HttpClientUtil.textual(response);
- JSONObject container = new JSONObject(textual);
- cachedRecordCount = container.getJSONObject("data").getInt("MatchCount");
- EntityUtils.consume(response.getEntity());
- response.close();
- }
- /**
- * Updates the ZIP code settings the web server will use to conduct data searches.
- *
- * @param zips
- * @throws IOException
- */
- public void sendZipSettings(String[] zips) throws IOException {
- this.lastSentZips = zips;
- StringBuilder zipsParamBuilder = new StringBuilder();
- if (zips.length > 0) {
- for (String s : zips) {
- zipsParamBuilder.append(s).append(" ");
- }
- zipsParamBuilder.setLength(zipsParamBuilder.length() - 1);
- }
- HttpPost post = new HttpPost(changeZipSettingsUrl + sessionId);
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("pastedZipCodes", zipsParamBuilder.toString()));
- params.add(new BasicNameValuePair("zipLookup", ""));
- params.add(new BasicNameValuePair("carrierRouteGrid", ""));
- params.add(new BasicNameValuePair("commit", "true"));
- post.setEntity(new UrlEncodedFormEntity(params));
- appendFakeHeaders(post);
- CloseableHttpResponse response = client.execute(post);
- String textual = HttpClientUtil.textual(response);
- JSONObject container = new JSONObject(textual);
- cachedRecordCount = container.getJSONObject("data").getInt("MatchCount");
- EntityUtils.consume(response.getEntity());
- response.close();
- }
- /**
- * Updates the SIC settings the web server will use to conduct data searches.
- *
- * @param sicLookups
- * @throws IOException
- */
- public void sendSicSettings(String[] sicLookups) throws IOException {
- this.lastSentSics = sicLookups;
- StringBuilder sicLookupParamBuilder = new StringBuilder();
- if (sicLookups.length > 0) {
- for (String s : sicLookups) {
- sicLookupParamBuilder.append(s).append(" ");
- }
- sicLookupParamBuilder.setLength(sicLookupParamBuilder.length() - 1);
- }
- HttpPost post = new HttpPost(changeSicSettingsUrl + sessionId);
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("pastedSicCodes", ""));
- params.add(new BasicNameValuePair("pastedNAICSCodes", ""));
- params.add(new BasicNameValuePair("sicLookup", sicLookupParamBuilder.toString()));
- params.add(new BasicNameValuePair("naicsLookup", ""));
- params.add(new BasicNameValuePair("numericalSic", ""));
- params.add(new BasicNameValuePair("pastedSic", ""));
- params.add(new BasicNameValuePair("primarySicOnly", "false"));
- params.add(new BasicNameValuePair("primaryNumericalSicOnly", "false"));
- params.add(new BasicNameValuePair("numericalNaics", ""));
- params.add(new BasicNameValuePair("pastedNaics", ""));
- params.add(new BasicNameValuePair("primaryNaicsOnly", "false"));
- params.add(new BasicNameValuePair("primaryNumericalNaicsOnly", "false"));
- params.add(new BasicNameValuePair("commit", "true"));
- post.setEntity(new UrlEncodedFormEntity(params));
- appendFakeHeaders(post);
- CloseableHttpResponse response = client.execute(post);
- String textual = HttpClientUtil.textual(response);
- JSONObject container = new JSONObject(textual);
- cachedRecordCount = container.getJSONObject("data").getInt("MatchCount");
- EntityUtils.consume(response.getEntity());
- response.close();
- }
- /**
- * Attempts to query a list of data entries from the web server.
- *
- * @param page
- * @param querySize
- * @return The JSON result from the web server
- * @throws IOException
- */
- private JSONObject queryListing(int page, int querySize) throws IOException {
- HttpPost post = new HttpPost(dataSearchUrl + sessionId);
- List<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair("iDisplayStart", Integer.toString(page * querySize)));
- params.add(new BasicNameValuePair("sEcho", Integer.toString(page + 1)));
- post.setEntity(new UrlEncodedFormEntity(params));
- appendFakeHeaders(post);
- CloseableHttpResponse response = client.execute(post);
- String textual = HttpClientUtil.textual(response);
- if (!textual.startsWith("{")) {
- throw new IOException("Invalid response received (not JSON)");
- }
- JSONObject container = new JSONObject(textual);
- if (!container.has("aaData")) {
- throw new IOException("Invalid response received (no aaData object in JSON response)");
- }
- return container;
- }
- /**
- * Will attempt to query for all data entries, with exception handling to avoid crashes.
- *
- * @param querySize
- * The size of each query chunk
- */
- public void safeQueryAll(int querySize) throws IOException {
- this.running = true;
- // store these here, because in the case of an exception
- // all state will be reset, including last sent information (while retrieving new session id)
- String[] cachedCounties = this.lastSentCounties;
- String[] cachedStates = this.lastSentStates;
- String[] cachedZips = this.lastSentZips;
- String[] cachedSics = this.lastSentSics;
- int queryCount = cachedRecordCount / querySize;
- for (int i = 0; i < queryCount; i++) {
- try {
- JSONObject container = queryListing(i, querySize);
- JSONArray rows = container.getJSONArray("aaData");
- for (int j = 0; j < rows.length(); j++) {
- JSONObject current = rows.getJSONObject(j);
- if (!current.has("state")) {
- throw new IOException("Invalid response received (row missing state)");
- } else if (!current.has("zIP")) {
- throw new IOException("Invalid response received (row zip)");
- } else if (!current.has("cityV2")) {
- throw new IOException("Invalid response received (row missing city)");
- } else if (!current.has("streetAddress")) {
- throw new IOException("Invalid response received (row missing street address)");
- } else if (!current.has("businessName")) {
- throw new IOException("Invalid response received (row missing business name)");
- } else if (!current.has("executiveName")) {
- throw new IOException("Invalid response received (row missing executive name)");
- } else if (!current.has("phone")) {
- throw new IOException("Invalid response received (row missing phone)");
- }
- Document stateDoc = Jsoup.parse(current.getString("state"));
- Document zipDoc = Jsoup.parse(current.getString("zIP"));
- Document cityDoc = Jsoup.parse(current.getString("cityV2"));
- Document streetDoc = Jsoup.parse(current.getString("streetAddress"));
- Document businessDoc = Jsoup.parse(current.getString("businessName"));
- Document executiveDoc = Jsoup.parse(current.getString("executiveName"));
- Document phoneDoc = Jsoup.parse(current.getString("phone"));
- String state = stateDoc.text();
- String zip = zipDoc.text();
- String city = cityDoc.text();
- String street = streetDoc.text();
- String business = businessDoc.text();
- String fullName = executiveDoc.text().trim();
- String phone = phoneDoc.text();
- SearchEntry e = new SearchEntry(state, zip, city, street, business, fullName, phone);
- for (Callback<SearchEntry> callback : parseCallbacks) {
- callback.callback(e);
- }
- }
- } catch (IOException e) {
- System.out.println("Error querying data -> attempting to relog (" + e.getMessage() + ")");
- while (true) {
- try {
- this.reset();
- this.login();
- this.sendAreaSettings(cachedCounties, cachedStates);
- this.sendZipSettings(cachedZips);
- this.sendSicSettings(cachedSics);
- break;
- } catch (Exception e2) {
- e2.printStackTrace();
- }
- }
- }
- if (!this.running) {
- break;
- }
- }
- this.running = false;
- }
- /**
- * Registers a Callback that'll be fired off when a new data entry is parsed from the web server.
- *
- * @param callback
- */
- public void registerParseCallback(Callback<SearchEntry> callback) {
- this.parseCallbacks.add(callback);
- }
- /**
- * @return If a data search is currently running or not
- */
- public boolean isRunningSearch() {
- return running;
- }
- /**
- * Stops the currently running data search after it's finished with the
- * query it's currently on.
- */
- public void stopRunning() {
- this.running = false;
- }
- /**
- * @return The amount of total data entry records in the last submitted search
- */
- public int getCachedRecordCount() {
- return this.cachedRecordCount;
- }
- /**
- * Appends fake headers to the provided HttpRequestBase to make it appear like a legitimate request
- * made from a web browser.
- *
- * @param base
- */
- private static void appendFakeHeaders(HttpRequestBase base) {
- base.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
- base.addHeader("Accept-Encoding", "gzip, deflate");
- base.addHeader("Connection", "keep-alive");
- base.addHeader("Host", "salesgenie.com");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement