JSOUP Wait for page to parsed - java

I have a JSOUP Login program that logs into a website and grabs info from the page. It works well, but it takes ~3 seconds for the information to be parsed into ArrayLists as JSOUP takes a while.
I also have a check to see if the correct page is loaded correctly. (It's just checking the ArrayLists to see if they are empty meaning the page isn't loaded)
public void onClick(View v) {
SourcePage sp = new SourcePage(user.getText().toString(), pass.getText().toString());
if(sp.isConnected()) { //Refer to the bottom of the next code box
Toast.makeText(getApplicationContext(), sp.getGradeLetters().get(0), Toast.LENGTH_SHORT).show();
startActivity(new Intent(MainActivity.this, gradepage.class));
}else {
Toast.makeText(getApplicationContext(), "Login Failed", Toast.LENGTH_SHORT).show();
}
}
private void login() {
Thread th = new Thread() {
public void run() {
try {
HashMap<String, String> cookies = new HashMap<>();
HashMap<String, String> formData = new HashMap<>();
Connection.Response loginForm = Jsoup.connect(URL)
.method(Connection.Method.GET)
.userAgent(userAgent)
.execute();
Document loginDoc = loginForm.parse();
String pstoken = loginDoc.select("#LoginForm > input[type=\"hidden\"]:nth-child(1)").first().attr("value");
String contextData = loginDoc.select("#contextData").first().attr("value");
String dbpw = loginDoc.select("#LoginForm > input[type=\"hidden\"]:nth-child(3)").first().attr("value");
String serviceName = "PS Parent Portal";
String credentialType = "User Id and Password Credential";
cookies.putAll(loginForm.cookies());
//Inserting all hidden form data things
formData.put("pstoken", pstoken);
formData.put("contextData", contextData);
formData.put("dbpw", dbpw);
formData.put("serviceName", serviceName);
formData.put("credentialType", credentialType);
formData.put("Account", USERNAME);
formData.put("ldappassword", PASSWORD);
formData.put("pw", PASSWORD);
Connection.Response homePage = Jsoup.connect(POST_URL)
.cookies(cookies)
.data(formData)
.method(Connection.Method.POST)
.userAgent(userAgent)
.execute();
mainDoc = Jsoup.parse(homePage.parse().html());
//Get persons name
NAME = mainDoc.select("div#sps-stdemo-non-conf").select("h1").first().text();
//Getting Grades for Semester 2
Elements grades = mainDoc.select("td.colorMyGrade").select("[href*='fg=S2']");
System.out.println(grades);
for (Element j : grades)
{
if (!j.text().equals("--")) {
String gradeText = j.text();
gradeLetter.add(gradeText.substring(0, gradeText.indexOf(" ")));
gradeNumber.add(Double.parseDouble(gradeText.substring(gradeText.indexOf(" ") + 1)));
}
}
Elements teachers = mainDoc.select("td[align='left']");
for (int i = 1; i < teachers.size(); i += 2)
{
String fullText = teachers.get(i).text().replaceAll("//s+", ".");
teacherList.add(fullText);
}
}catch (IOException e) {
System.out.println(e);
}
}
};
th.start();
}
public boolean isConnected() {
return (!(gradeLetter.isEmpty() || gradeNumber.isEmpty() || teacherList.isEmpty()));
}
The big problem is that the program (onClick) is giving the Toast "Login Failed" because the isConnected method doesn't wait for the page to load. How can I fix this?

Related

Connect Android to Laravel using http URL

I'm confused on how can I connect my android mobile to Laravel I've tried different ways but returns me an Java.ioFileNotFoundException:http://122.168...
I found out that the problem is the CSRF-TOKEN when I've tried disabling the CSRF-TOKEN in my laravel it works , what I tried I fetch first my CSRF-TOKEN and submit it with CSRF-TOKEN when buttons click but it didn't work either.
I used Plugin for Advanced-HttpURLConnection GITHUB LINK link
This is what I tried
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
FetchData fetchData = new FetchData("http://122.168.1.3/app/refreshtokens");
if (fetchData.startFetch()) {
if (fetchData.onComplete()) {
String fetchResult = fetchData.getResult();
try {
//getting the token from fetch data
JSONObject jsonObject = new JSONObject(fetchResult);
String csrfToken = jsonObject.getString("csrfToken");
String[] field = new String[3];
field[0] = "id_no";
field[1] = "password";
field[2] = "X-CSRF-TOKEN";
//Creating array for data
String[] data = new String[3];
data[0] = id_no;
data[1] = password;
data[2] = csrfToken;
PutData putData = new PutData("http://122.168.1.3/app/auth", "POST", field, data);
if (putData.startPut()) {
if (putData.onComplete()) {
String result = putData.getResult();
//just want to getData when success
Toast.makeText(getApplicationContext(), "Testt " + result, Toast.LENGTH_SHORT).show();
}
}
//End Write and Read data with URL
} catch (JSONException e) {
Toast.makeText(getApplicationContext(), "error catch " + e, Toast.LENGTH_SHORT).show();
}
}
}}
});

Very fast URL check

So I creating an android app where I need to check if a file exist on a remote server really fast because I have to test ~1000 links before the app become usable.
I currently call a function that return the URL if it's valid and null if not.
public String CheckUrl(String url) {
try {
URL urll = new URL(url);
HttpURLConnection huc = (HttpURLConnection) urll.openConnection();
huc.setRequestMethod("GET"); //OR huc.setRequestMethod ("HEAD");
huc.connect();
int code = huc.getResponseCode();
System.out.println(code);
if (code == 200) {
return url;
} else {
return null;
}
} catch (Exception e) {
return null;
}
}
and I use it like this:
for (Element episode : episodes) {
globalEpisodeCounter++;
localEpisodeCounter++;
MLP_Episode currentEpisode = new MLP_Episode();
Elements links = episode.getElementsByTag("a");
Element linkObj = links.get(0);
Element thumObj = linkObj.getElementsByTag("img").get(0);
Element titleObj = linkObj.getElementsByTag("b").get(0);
int notRealsead = episode.getElementsByClass("btn btn-sm btn-error").size();
Boolean epReleased = false;
if (notRealsead == 0) {
epReleased = true;
}
currentEpisode.url = "https://www.newlunarrepublic.fr" + linkObj.attributes().get("href");
currentEpisode.thumbUrl = "https://www.newlunarrepublic.fr" + thumObj.attributes().get("src");
currentEpisode.title = titleObj.text();
currentEpisode.released = epReleased;
currentEpisode.id_local = localEpisodeCounter;
currentEpisode.id_global = globalEpisodeCounter;
currentEpisode.in_season_num = seasonCounter;
if (epReleased) {
currentEpisode.url_vo_1080p = CheckUrl(
"---------/NLR-1080p-" + addZero(seasonCounter) + "x" + addZero(localEpisodeCounter) + ".webm");
}
epList.add(currentEpisode);
}
At the and end of the search the search thread call a function to update UI
But the down side of the function is that it's very slow 1-2 link/sec which ranslate in 15min waiting before the app is usable
So the answer was to run the check in a separate thread:
Thread thread = new Thread() {
#Override
public void run() {
try {
currentEpisode.url_vo_1080p = CheckUrl("------------/NLR-1080p-"+addZero(seasonCounter2)+"x"+addZero(localEpisodeCounter2)+".webm");
}
catch (Exception e) {}
}
};
thread.start();

jsoup gives null response when print is removed

I'm trying to login to a bank website using jsoup but I'm getting a NullPointerException when the line that prints the cookies is removed from the code. I know I should verify if the response is null but the problem is that the program works when I print the cookies.
Here is the code:
private class GetHomeTask extends AsyncTask<Void, Void, BitmapDrawable> {
protected BitmapDrawable doInBackground(Void... nothing) {
try {
Response home = Jsoup.connect(HOME_URL + "LoginKaptcha.jpg")
.userAgent(USER_AGENT)
.validateTLSCertificates(false)
.ignoreContentType(true)
.method(Method.GET)
.execute();
cookies = home.cookies();
//System.out.println(cookies); --> if commented, I get a NullPointerException when parsing the login page as pointed below.
ByteArrayInputStream inputStream = new ByteArrayInputStream(home.bodyAsBytes());
Bitmap bMap = BitmapFactory.decodeStream(inputStream);
return new BitmapDrawable(getApplicationContext().getResources(), bMap);
} catch (IOException e) {
}
return null;
}
#Override
protected void onPostExecute(BitmapDrawable bMap) {
setImage(bMap);
}
}
public void loginAction(View view) {
String[] userDetails = new String[3];
EditText userIdText = (EditText) findViewById(R.id.userIdField);
userDetails[0] = userIdText.getText().toString();
EditText userPasswordText = (EditText) findViewById(R.id.userPasswordField);
userDetails[1] = userPasswordText.getText().toString();
EditText captchaText = (EditText) findViewById(R.id.captchaField);
userDetails[2] = captchaText.getText().toString();
new LoginTask().execute(userDetails);
}
private class LoginTask extends AsyncTask<String[], Void, Response> {
protected Response doInBackground(String[]... userDetails) {
Response login = null;
try {
login = Jsoup.connect(HOME_URL + "login.action")
.data("cardHolder.userId", userDetails[0][0])
.data("cardHolder.userPassword", userDetails[0][1])
.data("captchaResponse1", userDetails[0][2])
.data("instName", instName)
.data("__checkbox_rememberMe", "true")
.userAgent(USER_AGENT)
.cookies(cookies)
.referrer(HOME_URL)
.validateTLSCertificates(false)
.method(Method.POST)
.execute();
} catch (IOException e) {
e.printStackTrace();
}
return login;
}
#Override
protected void onPostExecute(Response login) {
String userName = null;
try {
// --> NullPointerException (login is null) occurs here only when I comment the line that prints the cookies.
userName = login.parse().getElementsByClass("pageTitle").text();
} catch (IOException e) {
e.printStackTrace();
}
String token = login.url().toString().substring(54);
cookies = login.cookies();
Intent intent = new Intent(getApplicationContext(), DisplaySummaryActivity.class);
intent.putExtra(EXTRA_MESSAGE, userName + "&" + token);
startActivity(intent);
}
}
I tried to search the error but nothing is similar to this. Does anyone have an idea of what is the problem?
Thank you.
The problem was with the connection timeout. Jsoup uses 3s as default, so I've changed it to 10s using Jsoup.connect(url).timeout(10*1000).

WebCrawler with recursion

So I am working on a webcrawler that is supposed to download all images, files, and webpages, and then recursively do the same for all webpages found. However, I seem to have a logic error.
public class WebCrawler {
private static String url;
private static int maxCrawlDepth;
private static String filePath;
/* Recursive function that crawls all web pages found on a given web page.
* This function also saves elements from the DownloadRepository to disk.
*/
public static void crawling(WebPage webpage, int currentCrawlDepth, int maxCrawlDepth) {
webpage.crawl(currentCrawlDepth);
HashMap<String, WebPage> pages = webpage.getCrawledWebPages();
if(currentCrawlDepth < maxCrawlDepth) {
for(WebPage wp : pages.values()) {
crawling(wp, currentCrawlDepth+1, maxCrawlDepth);
}
}
}
public static void main(String[] args) {
if(args.length != 3) {
System.out.println("Must pass three parameters");
System.exit(0);
}
url = "";
maxCrawlDepth = 0;
filePath = "";
url = args[0];
try {
URL testUrl = new URL(url);
URLConnection urlConnection = testUrl.openConnection();
urlConnection.connect();
} catch (MalformedURLException e) {
System.out.println("Not a valid URL");
System.exit(0);
} catch (IOException e) {
System.out.println("Could not open URL");
System.exit(0);
}
try {
maxCrawlDepth = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
System.out.println("Argument is not an int");
System.exit(0);
}
filePath = args[2];
File path = new File(filePath);
if(!path.exists()) {
System.out.println("File Path is invalid");
System.exit(0);
}
WebPage webpage = new WebPage(url);
crawling(webpage, 0, maxCrawlDepth);
System.out.println("Web crawl is complete");
}
}
the function crawl will parse the contents of a website storing any found images, files, or links into a hashmap, for example:
public class WebPage implements WebElement {
private static Elements images;
private static Elements links;
private HashMap<String, WebImage> webImages = new HashMap<String, WebImage>();
private HashMap<String, WebPage> webPages = new HashMap<String, WebPage>();
private HashMap<String, WebFile> files = new HashMap<String, WebFile>();
private String url;
public WebPage(String url) {
this.url = url;
}
/* The crawl method parses the html on a given web page
* and adds the elements of the web page to the Download
* Repository.
*/
public void crawl(int currentCrawlDepth) {
System.out.print("Crawling " + url + " at crawl depth ");
System.out.println(currentCrawlDepth + "\n");
Document doc = null;
try {
HttpConnection httpConnection = (HttpConnection) Jsoup.connect(url);
httpConnection.ignoreContentType(true);
doc = httpConnection.get();
} catch (MalformedURLException e) {
System.out.println(e.getLocalizedMessage());
} catch (IOException e) {
System.out.println(e.getLocalizedMessage());
} catch (IllegalArgumentException e) {
System.out.println(url + "is not a valid URL");
}
DownloadRepository downloadRepository = DownloadRepository.getInstance();
if(doc != null) {
images = doc.select("img");
links = doc.select("a[href]");
for(Element image : images) {
String imageUrl = image.absUrl("src");
if(!webImages.containsValue(image)) {
WebImage webImage = new WebImage(imageUrl);
webImages.put(imageUrl, webImage);
downloadRepository.addElement(imageUrl, webImage);
System.out.println("Added image at " + imageUrl);
}
}
HttpConnection mimeConnection = null;
Response mimeResponse = null;
for(Element link: links) {
String linkUrl = link.absUrl("href");
linkUrl = linkUrl.trim();
if(!linkUrl.contains("#")) {
try {
mimeConnection = (HttpConnection) Jsoup.connect(linkUrl);
mimeConnection.ignoreContentType(true);
mimeConnection.ignoreHttpErrors(true);
mimeResponse = (Response) mimeConnection.execute();
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
String contentType = null;
if(mimeResponse != null) {
contentType = mimeResponse.contentType();
}
if(contentType == null) {
continue;
}
if(contentType.toString().equals("text/html")) {
if(!webPages.containsKey(linkUrl)) {
WebPage webPage = new WebPage(linkUrl);
webPages.put(linkUrl, webPage);
downloadRepository.addElement(linkUrl, webPage);
System.out.println("Added webPage at " + linkUrl);
}
}
else {
if(!files.containsValue(link)) {
WebFile webFile = new WebFile(linkUrl);
files.put(linkUrl, webFile);
downloadRepository.addElement(linkUrl, webFile);
System.out.println("Added file at " + linkUrl);
}
}
}
}
}
System.out.print("\nFinished crawling " + url + " at crawl depth ");
System.out.println(currentCrawlDepth + "\n");
}
public HashMap<String, WebImage> getImages() {
return webImages;
}
public HashMap<String, WebPage> getCrawledWebPages() {
return webPages;
}
public HashMap<String, WebFile> getFiles() {
return files;
}
public String getUrl() {
return url;
}
#Override
public void saveToDisk(String filePath) {
System.out.println(filePath);
}
}
The point of using a hashmap is to ensure that I do not parse the same website more than once. The error seems to be with my recursion. What is the issue?
Here is also some sample output for starting the crawl at http://www.google.com
Crawling https://www.google.com/ at crawl depth 0
Added webPage at http://www.google.com/intl/en/options/
Added webPage at https://www.google.com/intl/en/ads/
Added webPage at https://www.google.com/services/
Added webPage at https://www.google.com/intl/en/about.html
Added webPage at https://www.google.com/intl/en/policies/
Finished crawling https://www.google.com/ at crawl depth 0
Crawling https://www.google.com/services/ at crawl depth 1
Added webPage at http://www.google.com/intl/en/enterprise/apps/business/?utm_medium=et&utm_campaign=en&utm_source=us-en-et-nelson_bizsol
Added webPage at https://www.google.com/services/sitemap.html
Added webPage at https://www.google.com/intl/en/about/
Added webPage at https://www.google.com/intl/en/policies/
Finished crawling https://www.google.com/services/ at crawl depth 1
**Crawling https://www.google.com/intl/en/policies/ at crawl depth 2**
Added webPage at https://www.google.com/intl/en/policies/
Added webPage at https://www.google.com/intl/en/policies/terms/
Added webPage at https://www.google.com/intl/en/policies/privacy/
Added webPage at https://www.google.com/intl/en/policies/terms/
Added webPage at https://www.google.com/intl/en/policies/faq/
Added webPage at https://www.google.com/intl/en/policies/technologies/
Added webPage at https://www.google.com/intl/en/about/
Added webPage at https://www.google.com/intl/en/policies/
Finished crawling https://www.google.com/intl/en/policies/ at crawl depth 2
**Crawling https://www.google.com/intl/en/policies/ at crawl depth 3**
Notice that it parses http://www.google.com/intl/en/policies/ twice
You are creating a new map for each web-page. This will ensure that if the same link occurs on the page twice it will only be crawled once but it will not deal with the case where the same link appears on two different pages.
https://www.google.com/intl/en/policies/ appears on both https://www.google.com/ and https://www.google.com/services/.
To avoid this use a single map throughout your crawl and pass it as a parameter into the recursion.
public class WebCrawler {
private HashMap<String, WebPage> visited = new HashMap<String, WebPage>();
public static void crawling(Map<String, WebPage> visited, WebPage webpage, int currentCrawlDepth, int maxCrawlDepth) {
}
}
As you are also holding a map of the images etc you may prefer to create a new object, perhaps call it visited, and make it keep track.
public class Visited {
private HashMap<String, WebPage> webPages = new HashMap<String, WebPage>();
public boolean visit(String url, WebPage page) {
if (webPages.containsKey(page)) {
return false;
}
webPages.put(url, page);
return true;
}
private HashMap<String, WebImage> webImages = new HashMap<String, WebImage>();
public boolean visit(String url, WebImage image) {
if (webImages.containsKey(image)) {
return false;
}
webImages.put(url, image);
return true;
}
}

Permissions Error - Trying to get friends using android facebook sdk

I am trying to add a feature to my android app that allows users to "checkin" with other people tagged to the checkin.
I have the checkins method working no problem and can tag some one by adding the user ID as a parameter (see code below)
public void postLocationTagged(String msg, String tags, String placeID, Double lat, Double lon) {
Log.d("Tests", "Testing graph API location post");
String access_token = sharedPrefs.getString("access_token", "x");
try {
if (isSession()) {
String response = mFacebook.request("me");
Bundle parameters = new Bundle();
parameters.putString("access_token", access_token);
parameters.putString("place", placeID);
parameters.putString("Message",msg);
JSONObject coordinates = new JSONObject();
coordinates.put("latitude", lat);
coordinates.put("longitude", lon);
parameters.putString("coordinates",coordinates.toString());
parameters.putString("tags", tags);
response = mFacebook.request("me/checkins", parameters, "POST");
Toast display = Toast.makeText(this, "Checkin has been posted to Facebook.", Toast.LENGTH_SHORT);
display.show();
Log.d("Tests", "got response: " + response);
if (response == null || response.equals("") ||
response.equals("false")) {
Log.v("Error", "Blank response");
}
} else {
// no logged in, so relogin
Log.d(TAG, "sessionNOTValid, relogin");
mFacebook.authorize(this, PERMS, new LoginDialogListener());
}
} catch(Exception e) {
e.printStackTrace();
}
}
This works fine (I've posted it in case it is of help to anyone else!), the problem i am having is i am trying to create a list of the users friends so they can select the friends they want to tag. I have the method getFriends (see below) which i am then going to use to generate an AlertDialog that the user can select from which in turn will give me the id to use in the above "postLocationTagged" method.
public void getFriends(CharSequence[] charFriendsNames,CharSequence[] charFriendsID, ProgressBar progbar) {
pb = progbar;
try {
if (isSession()) {
String access_token = sharedPrefs.getString("access_token", "x");
friends = charFriendsNames;
friendsID = charFriendsID;
Log.d(TAG, "Getting Friends!");
String response = mFacebook.request("me");
Bundle parameters = new Bundle();
parameters.putString("access_token", access_token);
response = mFacebook.request("me/friends", parameters, "POST");
Log.d("Tests", "got response: " + response);
if (response == null || response.equals("") ||
response.equals("false")) {
Log.v("Error", "Blank response");
}
} else {
// no logged in, so relogin
Log.d(TAG, "sessionNOTValid, relogin");
mFacebook.authorize(this, PERMS, new LoginDialogListener());
}
} catch(Exception e) {
e.printStackTrace();
}
}
When i look at the response in the log it reads:
"got responce: {"error":{"type":"OAuthException", "message":"(#200) Permissions error"}}"
I have looked through the graphAPI documentation and searched for similar questions but to no avail! I'm not sure if i need to request extra permissions for the app or if this is something your just not allowed to do! Any help/suggestions would be greatly appreciated.
You might need the following permissions:
user_checkins
friends_checkins
read_friendlists
manage_friendlists
publish_checkins
Check the related ones from the API docs. Before that, make sure that which line causes this permission error and try to fix it.
The solution is to implement a RequestListener when making the request to the Facebook graph API. I have the new getFriends() method (see below) which uses the AsyncGacebookRunner to request the data.
public void getFriends(CharSequence[] charFriendsNames,String[] sFriendsID, ProgressBar progbar) {
try{
//Pass arrays to store data
friends = charFriendsNames;
friendsID = sFriendsID;
pb = progbar;
Log.d(TAG, "Getting Friends!");
//Create Request with Friends Request Listener
mAsyncRunner.request("me/friends", new FriendsRequestListener());
} catch (Exception e) {
Log.d(TAG, "Exception: " + e.getMessage());
}
}
The AsyncFacebookRunner makes the the request using the custom FriendsRequestListener (see below) which implements the RequestListener class;
private class FriendsRequestListener implements RequestListener {
String friendData;
//Method runs when request is complete
public void onComplete(String response, Object state) {
Log.d(TAG, "FriendListRequestONComplete");
//Create a copy of the response so i can be read in the run() method.
friendData = response;
//Create method to run on UI thread
FBConnectActivity.this.runOnUiThread(new Runnable() {
public void run() {
try {
//Parse JSON Data
JSONObject json;
json = Util.parseJson(friendData);
//Get the JSONArry from our response JSONObject
JSONArray friendArray = json.getJSONArray("data");
//Loop through our JSONArray
int friendCount = 0;
String fId, fNm;
JSONObject friend;
for (int i = 0;i<friendArray.length();i++){
//Get a JSONObject from the JSONArray
friend = friendArray.getJSONObject(i);
//Extract the strings from the JSONObject
fId = friend.getString("id");
fNm = friend.getString("name");
//Set the values to our arrays
friendsID[friendCount] = fId;
friends[friendCount] = fNm;
friendCount ++;
Log.d("TEST", "Friend Added: " + fNm);
}
//Remove Progress Bar
pb.setVisibility(ProgressBar.GONE);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FacebookError e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
Feel free to use any of this code in your own projects, or ask any questions about it.
You can private static final String[] PERMISSIONS = new String[] {"publish_stream","status_update",xxxx};xxx is premissions

Categories

Resources