我正在抓取一个网站以获取信息。片段包含两个检索数据然后绘制数据的方法。我必须异步处理数据以防止主线程被锁定。但是,当我运行代码时,很明显异步数据处理发生无序,这导致某些索引超出范围。我不确定该怎么办。我试图限制并行性,但没有帮助。我错过了什么?
private fun openinsiderGetData(): DataFrame<Any> {
val doc = Jsoup.connect("http://openinsider.com/search?q=TSLA").get()
val table = doc.select(".tinytable")
val dataMap = HashMap<String, ArrayList<String>>()
table.select("thead").select("tr").forEach {row ->
row.getElementsByTag("th").forEach { cell ->
dataMap[cell.text()] = ArrayList<String>()
}
}
// Get the table body cells
val keys = dataMap.keys.toList()
Log.d("Keys", keys.toString())
table.select("tbody").select("tr").forEach {row ->
var index = 0
for (i in 0..row.getElementsByTag("td").size) {
val key = keys[index]
Log.d("Key", key)
index += 1
Log.d("CELL TEXT:", row.getElementsByTag("td")[i].text())
dataMap[key]?.add(row.getElementsByTag("td")[i].text())
Log.d("DATA SO FAR", dataMap.toString())
}
}
Log.d("Map:", dataMap.toString())
val df = emptyDataFrame<Any>()
for (key in dataMap.keys) {
val column = columnOf(dataMap[key]) named key
df.add(column)
}
Log.d("Dataframe:", df.toString())
// process the data further
return df
}
}
private fun setupData() {
lifecycleScope.launch {
withContext(Dispatchers.Default.limitedParallelism(1)) {
data = openinsiderGetData()
val rows = data.values(byRows=true)
Log.d("ROWS:", rows.toString())
}
// TODO - Refactor Draw the table
我的数据日志给出:
{Insider Name=[D], Filing Date=[2023-08-08 20:01:17], 1w=[2023-08-04], Ticker=[TSLA], Title=[Taneja Vaibhav], Trade Type=[CFO, CAO], ΔOwn=[S - Sale+OE], 1d=[$261.00], Owned=[-4,000], Price=[104,504], Qty=[-4%], 6m=[-$1,044,000], X=[], Value=[], Trade Date=[], 1m=[]}
这显然是不正常的。我对这种情况如何发生以及如何预防感到困惑。
您的问题与并行处理数据无关。事实上,无论您是否限制并行性,您都不会在这里并行处理任何内容。您只启动了一个协程,因此没有任何东西可以并行运行。
正如在上一个问题中一样,您似乎假设映射中的键使用某种特定的顺序,它们有自己的索引。他们一般不会。将数据添加到地图后,如果我们获取其键,我们将以随机顺序获取它们。
解决该问题的一种方法是使用
LinkedHashMap
而不是 HashMap
。这是映射的特殊实现,它保留插入顺序。更好的是,使用 mutableMapOf()
函数,这是在 Kotlin 中创建地图的标准方法,在它的下面使用 LinkedHashMap
: mutableMapOf<String, List<String>>()
。
更明确的解决方案是在解析
thead
时创建一个键列表。或者我们可以将 ArrayList
对象存储在地图和列表中:
val dataMap = HashMap<String, ArrayList<String>>()
val dataList = ArrayList<ArrayList<String>>()
// while parsing thead:
val list = ArrayList<String>()
dataMap[cell.text()] = list
dataList += list
// while parsing the data:
dataList[index]?.add(row.getElementsByTag("td")[i].text())