Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm Scala中的web爬虫算法_Algorithm_Scala_Recursion - Fatal编程技术网

Algorithm Scala中的web爬虫算法

Algorithm Scala中的web爬虫算法,algorithm,scala,recursion,Algorithm,Scala,Recursion,我正在尝试创建一个算法,以递归的方式和功能性的方式进行web爬网。 我知道如何使用for循环、var变量和对其进行累加。 但我正努力递归地去做 关于我的代码的一些问题: 1.为什么def循环返回Any? 2.表单中有一些URL,其中getLinksPage抛出异常,返回None并中断循环。我该怎么处理呢? 3.如何使用Scala框架测试来测试这段代码 def getLinksPage(urlToCrawl: String): Option[List[String]] = { try {

我正在尝试创建一个算法,以递归的方式和功能性的方式进行web爬网。 我知道如何使用for循环、var变量和对其进行累加。 但我正努力递归地去做

关于我的代码的一些问题: 1.为什么
def循环
返回
Any
? 2.表单中有一些URL,其中getLinksPage抛出异常,返回None并中断循环。我该怎么处理呢? 3.如何使用Scala框架测试来测试这段代码

 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))
  • 您已经显式地将返回类型设置为Any。将其更新为
    List[String]
  • 减少异常处理的范围,使其仅包括可能引发异常的代码。使用
    进行理解
    应该有助于理解。另外,为了简单起见,只需返回<代码>列表>代码>而不是使用<代码>列表[String ] > <代码>选项[列表] <代码> >空< /COL>
  • 两种可能的选择:通过一个trait将
    conn
    实例混合在一起,该trait将允许您覆盖该值,或者更改您的函数以获取隐式
    conn
    ,然后您的单元测试可以模拟该隐式
    conn
  • 编辑

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

    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
        }
      }
    }
    

    谢谢关于第3点,如何使用递归http链接在本地模拟web服务器来测试web爬虫?哪个框架(ScalaMock…)?更新了答案,并提供了示例单元测试。不保证语法正确。:)我不明白你为什么用这个。而且这对我不起作用。我在编辑2中用我的代码复制了你的代码,但它不起作用。如果你有什么错误呢?在测试时,我的首选是使用可以混合到每个单独测试中的夹具在测试中设置代码。这允许我在测试不同的输入/输出时重用相同的夹具。我已经发布了我的代码,复制了给我带来错误的特性。