问题背景
最近想爬取某贝单词的词表,由于每个词表很大,某贝进行了分页,这就要求我要在获取当前页所有单词后再点击下一页,然后再获取当前页的单词,然后循环……
问题发生
获取完第一页的单词,自动单击下一页后,虽然能获得存放单词的html元素的WebElement对象,但是无法调用其getText方法(此时应该是浏览器还没把该元素的文本往上放,但是java代码的速度要比这个过程快,这时一调用getText就会导致异常,然后终止程序,特别烦)。
以下是伪代码:
List<String> words=new ArrayList<>();
List<String> chinese=new ArrayList<>();
WebElement nextPage=driver.findElement(By.xpath("//*[@id=\"root\"]/div/div[1]/div/div/div[2]/div[2]/div[11]/div/ul/li[9]"));
for(int i=1;i<zong;i++){
Thread.sleep(200);
//下面这句就会导致上述问题。
List<String>str=driver.findElements(By.cssSelector(".index_bottom__XLoPQ>span")).stream().map(WebElement::getText).toList();
chinese.addAll(str);
List<String>str2=driver.findElements(By.className("index_wordName__1lkbV")).stream().map(WebElement::getText).toList();
words.addAll(str2);
Thread.sleep(200);
nextPage.click();
}
于是我百度了下答案,但是很少有人用java来调用selenium,而且网上给出的答案都是互相抄袭,大致说的是要实现WebDriverWait类似的东西,我觉得太麻烦。也有答案是Thread.sleep,但是休眠的时间太不好控制了。
问题思考
上述可能抛出的异常,只是速度不一致导致的,这样的不一致不一定非要终止程序,我想可以这样:创建一个while(true)循环,在循环里创建一个try块,然后把容易造成不一致的代码放到try块中,然后catch,一旦catch到异常就continue,直到catch不到异常为止。当然,为了减少重复while的次数,可以在catch到异常时让线程休息一小段时间,然后再去循环。
问题解决的伪代码
List<String> words=new ArrayList<>();
List<String> chinese=new ArrayList<>();
WebElement nextPage=driver.findElement(By.xpath("//*[@id=\"root\"]/div/div[1]/div/div/div[2]/div[2]/div[11]/div/ul/li[9]"));
List<String>str;
List<String>str2
for(int i=1;i<zong;i++){
while(true){
try{
//把容易造成速度不一致的代码放try中
str=driver.findElements(By.cssSelector(".index_bottom__XLoPQ>span")).stream().map(WebElement::getText).toList();
str2=driver.findElements(By.className("index_wordName__1lkbV")).stream().map(WebElement::getText).toList();
}catch (Exception e){
Thread.sleep(200);//为减少循环次数,可以稍微休息一会
continue;
}
//catch不到异常时
chinese.addAll(str);
words.addAll(str2);
break;
}
nextPage.click();
}
声明
由于catch捕捉的异常没有进行细分,所以在用该方法时,需要保证自己的代码是正确的。
大家若有更简单的方法,欢迎评论区讨论。