javascript java android web-scraping jsoup

javascript - Android: Parse JS generó URL con JSOUP



web-scraping (1)

( Consulte ACTUALIZACIÓN a continuación , la primera solución aceptada no cumplió con el requisito de Android, pero se deja como referencia).

Solución de escritorio

HtmlUnit no parece capaz de manejar este sitio (a menudo el caso, últimamente). Por lo tanto, tampoco tengo una solución java simple, pero podría usar PhantomJS : descargue el binario para su sistema operativo, cree un archivo de script, inicie el proceso desde su código java y analice la salida con un analizador dom como jsoup .

Archivo de script (aquí llamado simple.js):

var page = require(''webpage'').create(); var fs = require(''fs''); var system = require(''system''); var url = ""; var fileName = "output"; // first parameter: url // second parameter: filename for output console.log("args length: " + system.args.length); if (system.args.length > 1) { url=system.args[1]; } if (system.args.length > 2){ fileName=system.args[2]; } if(url===""){ phantom.exit(); } page.settings.userAgent = ''Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36''; page.settings.loadImages = false; page.open(url, function(status) { console.log("Status: " + status); if(status === "success") { var path = fileName+''.html''; fs.write(path, page.content, ''w''); } phantom.exit(); });

Código Java (ejemplo para obtener título y cover-url):

try { //change path to phantomjs binary and your script file String outputFileName = "srulad"; String phantomJSPath = "phantomjs" + File.separator + "bin" + File.separator + "phantomjs"; String scriptFile = "simple.js"; String urlParameter = "http://srulad.com/#page-2"; new File(outputFileName+".html").delete(); Process process = Runtime.getRuntime().exec(phantomJSPath + " " + scriptFile + " " + urlParameter + " " + outputFileName); process.waitFor(); Document doc = Jsoup.parse(new File(outputFileName + ".html"),"UTF-8"); // output.html is created by phantom.js, same path as page.js Elements elements = doc.select("#list_page-2 > div"); for (Element element : elements) { System.out.println(element.select("div.l-description.float-left > div:nth-child(1) > a").first().attr("title")); System.out.println(element.select("div.l-image.float-left > a > img.lazy").first().attr("data-original")); } } catch (IOException | InterruptedException e) { e.printStackTrace(); }

Salida:

სიყვარული და მოწყალება / Love & Mercy http://srulad.com/assets/uploads/42410_Love_and_Mercy.jpg მუზა / The Muse http://srulad.com/assets/uploads/43164_large_qRzsimNz0eDyFLFJcbVLIxlqii.jpg ...

ACTUALIZAR

El análisis de sitios web con contenido dinámico basado en JavaScript en Android es posible utilizando WebView y jsoup. La siguiente aplicación de ejemplo utiliza un WebView con JavaScript habilitado para representar un sitio web dependiente de JavaScript. Con JavascriptInterface, se devuelve la fuente html, analizada con jsoup y, como prueba de concepto, los títulos y las URL de las imágenes de portada se utilizan para completar ListView. Los botones disminuyen o incrementan el número de página que desencadena una actualización de ListView. Nota: probado en un dispositivo Android 5.1.1 / API 22.

agregue permiso de internet a su AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/page_down" android:id="@+id/buttonDown" android:layout_weight="0.5" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/page_up" android:id="@+id/buttonUp" android:layout_weight="0.5" /> </LinearLayout> <ListView android:layout_width="match_parent" android:layout_height="0dp" android:id="@+id/listView" android:layout_gravity="bottom" android:layout_weight="0.5" /> </LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity { private final Handler uiHandler = new Handler(); private ArrayAdapter<String> adapter; private ArrayList<String> entries = new ArrayList<>(); private ProgressDialog progressDialog; private class JSHtmlInterface { @android.webkit.JavascriptInterface public void showHTML(String html) { final String htmlContent = html; uiHandler.post( new Runnable() { @Override public void run() { Document doc = Jsoup.parse(htmlContent); Elements elements = doc.select("#online_movies > div > div"); entries.clear(); for (Element element : elements) { String title = element.select("div.l-description.float-left > div:nth-child(1) > a").first().attr("title"); String imgUrl = element.select("div.l-image.float-left > a > img.lazy").first().attr("data-original"); entries.add(title + "/n" + imgUrl); } adapter.notifyDataSetChanged(); } } ); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.listView); adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, entries); listView.setAdapter(adapter); progressDialog = ProgressDialog.show(this, "Loading","Please wait...", true); progressDialog.setCancelable(false); try { final WebView browser = new WebView(this); browser.setVisibility(View.INVISIBLE); browser.setLayerType(View.LAYER_TYPE_NONE,null); browser.getSettings().setJavaScriptEnabled(true); browser.getSettings().setBlockNetworkImage(true); browser.getSettings().setDomStorageEnabled(false); browser.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); browser.getSettings().setLoadsImagesAutomatically(false); browser.getSettings().setGeolocationEnabled(false); browser.getSettings().setSupportZoom(false); browser.addJavascriptInterface(new JSHtmlInterface(), "JSBridge"); browser.setWebViewClient( new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { progressDialog.show(); super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { browser.loadUrl("javascript:window.JSBridge.showHTML(''<html>''+document.getElementsByTagName(''html'')[0].innerHTML+''</html>'');"); progressDialog.dismiss(); } } ); findViewById(R.id.buttonDown).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { uiHandler.post(new Runnable() { @Override public void run() { int page = Integer.parseInt(browser.getUrl().split("-")[1]); int newPage = page > 1 ? page-1 : 1; browser.loadUrl("http://srulad.com/#page-" + newPage); browser.loadUrl(browser.getUrl()); // not sure why this is needed, but doesn''t update without it on my device if(getSupportActionBar()!=null) getSupportActionBar().setTitle(browser.getUrl()); } }); } }); findViewById(R.id.buttonUp).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { uiHandler.post(new Runnable() { @Override public void run() { int page = Integer.parseInt(browser.getUrl().split("-")[1]); int newPage = page+1; browser.loadUrl("http://srulad.com/#page-" + newPage); browser.loadUrl(browser.getUrl()); // not sure why this is needed, but doesn''t update without it on my device if(getSupportActionBar()!=null) getSupportActionBar().setTitle(browser.getUrl()); } }); } }); browser.loadUrl("http://srulad.com/#page-1"); if(getSupportActionBar()!=null) getSupportActionBar().setTitle(browser.getUrl()); } catch (Exception e) { e.printStackTrace(); } } }

estoy tratando de analizar la URL generada por Bootstrap`s Bootpage.js que se parece a https://example.com/#page-2 pero JSOUP no puede analizarla y muestra la url principal. cómo obtener un enlace normal desde Bootpage o cómo hacer que JSOUP lo analice.

Código de análisis:

Jsoup.connect("https://example.com/#page-2").followRedirects(true).get();