The following code ran on a java file on my computer gives the correct result of "/pws/client/pdf/offers-in-store-10-11-16.pdf"
String pdfLink= null;
try {
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").get();
Element links = doc.select("a[title=\"Download offers in store\"]").first();
System.out.println(links.attr("href"));
} catch (IOException e) {
//e.printStackTrace();
}
However when I run the code on my android device in an app where it is activated by the button press,I get a null pointer exception on "pdfLink=links.attr("href");" so it isnt finding the link "/pws/client/pdf/offers-in-store-10-11-16.pdf" for whatever reason.In my android app the code is on a onclick listener of a button and I have stepped through the code,it does activate the on click and runs the right lines of code but for whatever reason JSOUP is not finding the link.Below is the android code
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnFetchData = (Button) findViewById(R.id.buttonTest);
btnFetchData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new FetchWebsiteData().execute();
}
});
}
private class FetchWebsiteData extends AsyncTask<Void, Void, Void> {
private String pdfLink = "didnt work";
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
try {
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").get();
//Elements links = doc.select("a[title=\"Download offers in store\"]");
Element links = doc.select("a[title=\"Download offers in store\"]").first();
pdfLink=links.attr("href");
} catch (IOException e) {
//e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
TextView txttitle = (TextView) findViewById(R.id.resultTextView);
txttitle.setText(pdfLink);
}
}
}
the mobile browser user-agent differs from the desktop browser; therefore, the HTML responses differ. In order to get the same result you have to set a desktop user-agent. Change this line :
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").get();
to:
Document doc = Jsoup.connect("http://www.dunnesstores.com/offer20/food-wine/fcp-category/home").userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0").get();
Related
I'm a beginner at android and I'm trying to make an app that get values from a html file hosted in a webserver that gets data from sensors of an arduino. But JSoup only gets the first value, i don't know how to get the values that changed.
Here is the MainAcivity.java code:
Public class MainActivity extends AppCompatActivity {
final String TAG = this.getClass().getSimpleName();
private AnimationDrawable creepyAnimation;
private ImageView creepyImage;
private TextView result;
RequestQueue requestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
creepyImage = (ImageView) findViewById(R.id.creepy);
creepyImage.setBackgroundResource(R.drawable.animation);
creepyAnimation = (AnimationDrawable) creepyImage.getBackground();
requestQueue = Volley.newRequestQueue(this);
result = (TextView) findViewById(R.id.textView);
getWebSite();
}
private void getWebSite(){
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
Document doc = (Document) Jsoup.connect("http://munhoz-unifei.000webhostapp.com/").get();
Element valor1 = doc.getElementById("sala");
Element valor2 = doc.getElementById("quarto");
builder.append(valor1.attr("sala")).append("xxx: ").append(valor1.text()).append("\n");
builder.append(valor2.attr("quarto")).append("lalala: ").append(valor2.text()).append("\n");
/*
for (Element element : valor){
builder.append(element.attr("sala"))
.append("\n").append("text: ").append(element.text());
}
*/
}catch (IOException e){
builder.append("ERROR: ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(builder.toString());
}
});
}
}).start();
}
}
i just want to get the values to change on the app as it changes on the website. Could someone give me a hint or an example of how to do this work?
Jsoup can only parse or process the html that is sent by the server.
Anything part of the DOM that is generated by the javascript on the client's end can't be parsed through Jsoup.
What you can try is selenium web automation to obtain the html rendered by the browser.
There is a problem when it tries to page in a normal java class everything works fine, but if this is done already in the android app, the answer comes "you don't have permission to access" while the user-agent is specified in the android manifest has the permission to use the Internet and all this in a separate thread, can someone faced with this problem
public void onClick(View view)
{
new Thread(new Runnable() {
#Override
public void run()
{
go();
}
}).start();
}
private void go()
{
try {
document = Jsoup.connect("http://issa.beltelecom.by/main.html").userAgent("Chrome 53.0.2785.143").ignoreHttpErrors(true).get();
} catch (IOException e) {
e.printStackTrace();
}
}
It seems to be important to set the Accept header field (note: tested on Android 5.1.1 device).
In general: if the connection is refused using jsoup, inspect the requests (for example using the networks tab in the chrome dev tools/F12) and add missing header fields.
Example Code
String userAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36";
String url = "https://issa.beltelecom.by/main.html";
String acceptValue = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
String host = "issa.beltelecom.by";
document = Jsoup.connect(url).header("Accept",acceptValue).header("Host", host).userAgent(userAgent).get();
You can try this, set your OnClickListener to call the background task.
new MyAsyncTask().execute();
Then perform your task
private class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
protected void onPreExecute() {
super.onPreExecute();
//do anything here
}
protected Boolean doInBackground(Void...param) {
Document document = null;
try {
document = Jsoup.connect(getString(R.string.your_url_string)).get();
} catch (IOException e) {
e.printStackTrace();
}
if (document != null) {
Elements yourElements = document.select("#element_id");
//Do anything here
return true;
}
//Document is null
return false;
}
protected void onPostExecute(Boolean result) {
if(result==true) {
// do this
}
}
}
I am currently using an AsyncTask to fetch the JSON array when pressing a button. After that i have another button called ParseJson which opens a new activity in which a list is shown with the JSONArray.
What i would like, is to have one button instead of 2, but since the getJSON button (first button above) is starting a backgroundtask which needs to be finnished first, before launching the other activity (ParseJSON button), this doesnt work in one button right now.
I heard something about using a loading dialog, but i am quite new to this and have no idea how to solve it.
This is the code i use, but i also need the the value from the Textview in the background task. I will send the value of the textview to a php file (by POST) which fetches the data from the database.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void getJSON(View view) {
TextView txv = (TextView) findViewById(R.id.orderID);
txv.getText().toString;
//I need this value in the backgroundtask later
new BackgroundTask().execute();
}
class BackgroundTask extends AsyncTask<Void, Void, String>
{
String json_url = "MYJSONURL";
String JSON_STRING;
#Override
protected String doInBackground(Void... params) {
try {
URL url = new URL(json_url);
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
while ((JSON_STRING = bufferedReader.readLine())!=null)
{
stringBuilder.append(JSON_STRING+"\n");
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
return stringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
json_string = result;
}
}
public void parseJSON(View view)
{
if(json_string==null)
{
Toast.makeText(getApplicationContext(), "First Get JSON", Toast.LENGTH_LONG).show();
}
else
{
Intent intent = new Intent(this, DisplayListView.class);
intent.putExtra("json_data", json_string);
startActivity(intent);
}
}
Instead of starting the AsyncTask by a button press you code in a way by which it can be started as soon as your main activity is launched. Use onProgressUpdate method of the AsyncTask which will show some progress, once that method is finished your data is loaded. Then you use one button to parse and display the data in the list.
You may refer this to know more about AsyncTask methods
You can have a look at the below code to understand how communication can happen between an activity and AsyncTask. For simplicity I have a count loop running inside AsyncTask which will update the progress on the activity.
Please be warned that this code communicates with the same activity which started the AsyncTask. So, if you would like to perform any such background task, you should be having the AsyncTask attached to your second activity.
public class MainActivity extends Activity {
private ProgressBar mProgress;
private int mProgressStatus = 0;
TextView percentage = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgress = (ProgressBar) findViewById(R.id.progress_bar);
percentage = (TextView) findViewById(R.id.percentage);
new CountProgress().execute();
}
class CountProgress extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
mProgress.setProgress(0);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... unused) {
for (int i=0; i<101;i++ ) {
if (isCancelled())
break;
publishProgress(i);
SystemClock.sleep(200);
}
return(null);
}
#Override
protected void onProgressUpdate(Integer... progress) {
if (!isCancelled()) {
mProgress.setVisibility(View.VISIBLE);
// updating progress bar value
mProgress.setProgress(progress[0]);
// updating progess percentage text
percentage.setText(progress[0].toString() + "%");
}
}
#Override
protected void onPostExecute(Void unused) {
Toast.makeText(getApplicationContext(), R.string.done, Toast.LENGTH_SHORT).show();
}
}
}
A full working app code can be downloaded from here and you can extend it further for your needs.
I am creating an app to fetch XKCD comics (just for learning purpose). I am using JSoup to fetch comic title and url of the image and Universal Image Loader to post the image in ImageView. However I'm facing some problems. Here is my main activity.
public class MainActivity extends Activity {
private static final String TAG = "MyApp";
ImageView xkcdImgIV;
TextView titleTV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
xkcdImgIV=(ImageView) findViewById(R.id.xkcdImgIV);
titleTV=(TextView) findViewById(R.id.titleTV);
try{
new AsyncImg().execute(new String[]{"http://www.xkcd.com/"});
} catch(NullPointerException e){
Log.d(TAG,"Null pointer exception")
}
}
private class AsyncImg extends AsyncTask<String,Void,Void>{
Document doc;
Elements elXkcdTitle;
Elements elXkcdImgUrl;
#Override
protected Void doInBackground(String... arg) {
try {
doc = Jsoup.connect(arg[0]).timeout(0).get();
elXkcdTitle=doc.select("#ctitle");
elXkcdImgUrl=doc.select("#comic img");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
titleTV.setText(elXkcdTitle.first().text());
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init( ImageLoaderConfiguration.createDefault(getApplicationContext() ));
imageLoader.displayImage(elXkcdImgUrl.first().attr("src"), xkcdImgIV);
}
}
}
There is no network activity. I've given the Internet access permission to the app. Moreover Logcat doesn't show any error. Both Jsoup and Universal Image Loader JARS have been included in build path. Feel free to ask for additional info.
I'm trying to add import contacts from gmail account function in my android app. So the first problem is to get access token from gmail. I've found that there is GoogleAuthUtil class which can help me with it.
Here is my code:
private void importContactsFromGmail() {
showProgressDialog();
GetTokenTask getTokenTask = new GetTokenTask();
getTokenTask.execute();
String token = "";
try {
token = getTokenTask.get();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(token);
hideProgressDialog();
}
private class GetTokenTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String token = "";
try {
token = GoogleAuthUtil.getToken(activity, <My_gmail_account>, "https://www.google.com/m8/feeds/");
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
}
Now after calling GoogleAuthUtil.getToken my app completely freezes(no errors in Logcat). I completely stuck and I need your help.
What is wrong with my code? Maybe I should import contacts in some other way?
Not sure if this is related but calling the .get() method on the main thread is not correct because is blocking method.
What if you use the AsyncTask in this way?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new GetTokenTask().execute();
}
static class GetTokenTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... unused) {
String token = "";
try {
token = GoogleAuthUtil.getToken(activity, <My_gmail_account>, "https://www.google.com/m8/feeds/");
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
#Override
protected void onPostExecute(String token) {
Toast.makeText(MainActivity.this, token, Toast.LENGTH_SHORT).show();
}
}
}
(I wrote without compiling it, maybe it needs to be adjusted)
On Android devices, Gmail contacts are synced locally onto the device and are available via a public Contacts Provider, therefore there's no reason you'd need to use the Google API to pull what is already available. There is a whole training series dedicated specifically to retrieving a list of contacts.
Note that the Contacts training series does assume you have knowledge of Content Providers already, so it may be helpful to read up on the basics of Content Providers as well.