概要: 私の Jsoup パーサーは単独では完全に機能しますが、Android アプリケーションの AsyncTask タスク クラスの 1 つにコピー アンド ペーストすると値を収集できません。2 次元配列は null だけで埋められて返されます。
長いバージョン: 私は、Jsoup を介してページ スクレイピングを使用して、さまざまなブログからコンテンツをプルして表示するアプリケーションに取り組んできました。これまでにいくつかのパーサーを作成しましたが、すべて期待どおりに動作するようです。残念ながら、私の最新のパーサー (nyc-shows.brooklynvegan.com 用に作成) には問題がありました。
これは、print ステートメントが追加されたメイン メソッドによって呼び出されるパーサー メソッド自体です。これを自分で実行します。それは機能します(完全ではありませんが、機能します)。
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Main {
static String TAG_EVENT = "li.ds-entry";
static String TAG_TITLE = ".ds-entry-title";
static String TAG_LOCATION = ".location";
static String TAG_DATE_AND_TIME = ".ds-date";
static String TAG_TICKET_URL = ".ds-buy-tickets";
static String FEED_URL = "http://nyc-shows.brooklynvegan.com/";
public static void main(String[] args) throws IOException {
String values[][] = new String[50][6];
values = getFeedItems();
for (int i=0; i<values.length; i++) {
for (int j=0; j<6; j++) {
System.out.println(values[i][j]);
}
System.out.println("-----------------");
}
}
public static String[][] getFeedItems() throws IOException {
Document doc = null;
String values[][] = new String[50][6];
try{
doc = Jsoup.connect(FEED_URL).timeout(0).get();
Elements events = doc.select(TAG_EVENT);
String delimSpace = "[ ]";
int i = 0;
for (Element event : events) {
//Set event title
Element title = event.select(TAG_TITLE).first();
String titleString = title.text();
if (title != null) {
boolean isFake = checkFake(titleString);
if (!isFake) {
values[i][0] = titleString;
}
else {
continue;
}
}
//Set event date and time i guess
Element dateAndTime = event.select(TAG_DATE_AND_TIME).first();
if (dateAndTime != null) {
String[] dateAndTimeTokens = dateAndTime.text().split(delimSpace);
String date = dateAndTimeTokens[1];
String time = dateAndTimeTokens[3];
values[i][1] = date;
values[i][2] = time;
}
//Set price (tbd)
values[i][3] = "See Ticket";
//Set location
Element location = event.select(TAG_LOCATION).first();
if (location != null) {
values[i][4] = location.text();
}
//Set ticket urls
Element ticketContainer = event.select(TAG_TICKET_URL).first();
if (ticketContainer != null) {
String ticket = ticketContainer.select("a").attr("href");
values[i][5] = ticket;
}
else {
values[i][3] = "Free";
}
i++;
} //End of event loop
} //End of try clause
catch (IOException e) {
e.printStackTrace();
}
return values;
}
public static boolean checkFake(String s) {
boolean isFake = false;
String[] days = {"Today", "Tomorrow", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
for (int i=0; i<days.length; i++) {
if (s.contains(days[i])) {
isFake = true;
return isFake;
}
}
return isFake;
}
}
ここで、ロード画面が表示されている間にアプリケーションによってバックグラウンドで実行されるように、AsyncTask に転送されたのとまったく同じメソッドを次に示します。
package com.example.nylist;
import java.io.IOException;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class BVParser extends AsyncTask<Void, Void, String[][]> {
static String TAG_EVENT = "li.ds-entry";
static String TAG_TITLE = ".ds-entry-title";
static String TAG_LOCATION = ".location";
static String TAG_DATE_AND_TIME = ".ds-date";
static String TAG_TICKET_URL = ".ds-buy-tickets";
static String FEED_URL = "http://nyc-shows.brooklynvegan.com/";
Context context;
Activity activity;
public BVParser(Activity context) {
this.context = context.getApplicationContext();
this.activity = context;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(context, "Fetching...", Toast.LENGTH_LONG).show();
}
@Override
protected String[][] doInBackground(Void... param) {
String values[][] = new String[50][6];
try {
values = getFeedItems();
}
catch (IOException e) {
Log.d("ASSERT", "Exception occured during doInBackground", e);
e.printStackTrace();
}
Log.d("ASSERT", ("values successfully returned by doInBackground, first title is: "+values[0][0]));
return values;
}
protected void onPostExecute(String[][] result) {
super.onPostExecute(result);
int eventCount = result.length;
Log.d("ASSERT", ("event count in onPostExecute is: "+eventCount));
ListRow[] listrow_data = new ListRow[eventCount];
ListRow temp;
for (int i=0; i<eventCount; i++) {
if (result[i] != null) {
temp = new ListRow(context, result[i][0], result[i][1], result[i][2],
result[i][3], result[i][4], result[i][5], i);
listrow_data[i] = temp;
}
}
((EventList) activity).setList(listrow_data);
}
public String[][] getFeedItems() throws IOException {
Document doc = null;
String values[][] = new String[50][6];
int i = 0;
try{
Log.d("ASSERT","Made it to try block");
doc = Jsoup.connect(FEED_URL).timeout(0).get();
Elements events = doc.select(TAG_EVENT);
Log.d("ASSERT","printing events, whatever it is: "+events);
String delimSpace = "[ ]";
//******THIS LOOP NEVER BEGINS*****//
for (Element event : events) {
Log.d("ASSERT","Made it to getFeedItems's main for loop");
//Set event title
Element title = event.select(TAG_TITLE).first();
String titleString = title.text();
Log.d("ASSERT","This title is: "+titleString);
boolean isFake = checkFake(titleString);
if (!isFake) {
values[i][0] = titleString;
}
else {
continue;
}
//Set event date and time i guess
Element dateAndTime = event.select(TAG_DATE_AND_TIME).first();
if (dateAndTime != null) {
String[] dateAndTimeTokens = dateAndTime.text().split(delimSpace);
String date = dateAndTimeTokens[1];
String time = dateAndTimeTokens[3];
values[i][1] = date;
values[i][2] = time;
}
//Set price
values[i][3] = "See Ticket";
//Set location
Element location = event.select(TAG_LOCATION).first();
if (location != null) {
values[i][4] = location.text();
}
//Set ticket urls
Element ticketContainer = event.select(TAG_TICKET_URL).first();
if (ticketContainer != null) {
String ticket = ticketContainer.select("a").attr("href");
values[i][5] = ticket;
}
else {
values[i][3] = "Free";
}
i++;
} //End of event loop
} //End of try clause
catch (IOException e) {
Log.d("ASSERT","Exception during getFeedItems");
e.printStackTrace();
}
Log.d("ASSERT","The first title in getFeedItems before returning is: "+values[0][0]);
return values;
}
private static boolean checkFake(String s) {
boolean isFake = false;
String[] days = {"Today", "Tomorrow", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
for (int i=0; i<days.length; i++) {
if (s.contains(days[i])) {
isFake = true;
return isFake;
}
}
return isFake;
}
}
デバッグの試み:
問題をデバッグするために、コード全体にログ ステートメントを追加しました。これを実行すると、getFeedItems() 自体のどこか、特に「try」ブロック内で問題が発生しているように見えることがわかります。try ステートメントの先頭にログ ステートメントが表示されますが、実行される for ループevents
はまったく実行されません。これは、最初のログ ステートメントが出力されないためです。
質問:events
ループ スルーが始まらない
理由を誰か説明できますか? events
null である場合、その理由は? それ自体で実行されているメソッドと AsyncTask 内で実行されているメソッドとの間に矛盾があるのはなぜですか? 私は髪をかきむしってきました。このパーサーのロジックは、私が書いた (動作中の) 他のパーサーのロジックとほとんど同じですが、これは null しかない 2 次元配列を返しています。論理エラーがどこにあるかを理解するのに苦労していますが、タイプミスを見つけることができないようです.
PS: これを私の他のパーサーと比較すると役立つ場合は、お知らせください。ソースを投稿します。前もって感謝します。