首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Scala中的web爬虫算法

Scala中的web爬虫算法
EN

Stack Overflow用户
提问于 2017-10-20 15:07:19
回答 1查看 1.4K关注 0票数 2

我正在尝试创建一个算法,以递归和功能的方式进行web爬行。我知道如何使用循环、var变量并在其上进行累积。但我很难递归地去做。

有关我的代码的一些问题: 1.为什么def loop返回Any?2.表单http://..../example.zip中有一些getLinksPage抛出异常、返回None并中断循环的URL。如何处理它? 3.如何使用Scala框架测试测试这段代码?

代码语言:javascript
运行
复制
 def getLinksPage(urlToCrawl: String): Option[List[String]] = {
    try {
      val conn = Jsoup.connect(urlToCrawl)
      val doc = conn.get()
      val elements = doc.select("a[href]")
      val elementsSc = elements.asScala
      val links = elementsSc.map(_.attr("abs:href")).toSeq
      val linksURL = links.map(new URL(_))

      val tartgetURL = (new URL(urlToCrawl)).getHost
      val linksLocalURL  = linksURL.filter(_.getHost == tartgetURL).map(_.toString).toList
      Some(linksLocalURL)
    }
    catch {
      case e: Exception => None
    }
  }

  def loop(l:Option[List[String]], acc: List[String]): Any = l match {
    case Some(Nil) => acc
    case Some(hd::tl) => if (!acc.contains(hd))   loop(getLinksPage(hd),hd::acc)
                        else  loop(Option(tl), acc)
    case None => acc

  }

 loop(getLinksPage(mainURL), List(mainURL))
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-10-20 17:15:13

  1. 您已经显式地将返回类型设置为Any。将其更新为List[String]
  2. 将异常处理的范围缩小到只包含可能引发异常的代码。使用for comprehension应该有助于这一点。同样为了简单起见,可以考虑只返回一个List,而不是使用List[String].empty返回一个Option[List]
  3. 两个潜在的选项:通过一个特性混合您的conn实例,该特性将允许您覆盖值或更改函数以接受隐式conn,然后单元测试可以模拟它。

编辑

下面是一个spitball示例,说明如何使用getLinksPageloop作为独立单元使用ScalaTest测试您的ScalaTest函数。免责声明:语法可能不是100%;根据需要进行调整。

代码语言:javascript
运行
复制
case class Crawler() {
  def getConnection(url: String) = Jsoup.connect(url)

  def getLinksPage(urlToCrawl: String): Option[List[String]] = {
    val conn = getConnection(urlToCrawl)

    ...
  }
}

class CrawerSpec extends WordSpec with MockFactory {

  trait LinksFixture {

    val connection = mock[Connection]
    val getConnection = mockFunction[String, Connection]

    lazy val crawler = new Crawler() {
      override def getConnection(url: String) = LinksFixture.this.getConnection(url)
    }
  }

  trait LoopFixture {

    val getLinksPage = mock[String, Option[List[String]]]

    lazy val crawler = new Crawler() {
      override def getLinksPage(url: String) = LoopFixture.this.getLinksPage(url)
    }
  }

  "getLinksPage" should {

    "return the links" in new LinksFixture {

      val url = "http://bad-wolf"

      getConnection expects(url) returning connection
      // add other expects on connection

      crawler.getLinksPage(url) shouldBe expected // define expected
    }
  }

  "loop" should {

    "loop over the links" in new LoopFixture {

      getLinksPage expects(*) onCall {
        _ match {
          case "a" => Some(List("b","c"))
          case "b" => Some(List("d"))
          case _ => None
        }
      }
      // add any other expects

      crawler.loop(Some(List("a")), List.empty[String]) shouldBe // define expected
    }
  }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46852052

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档