精华内容
下载资源
问答
  • 本文将会详细介绍Jsoup的使用方法,10分钟搞定Java爬虫HTML解析。    Jsoup可以直接解析某个URL地址、HTML文本内容,它提供非常丰富的处理Dom树的API。如果你使用过JQuery,那你一定会非常熟悉。    Jsoup最强大...

    Java爬虫解析HTML文档的工具有:htmlparser, Jsoup。本文将会详细介绍Jsoup的使用方法,10分钟搞定Java爬虫HTML解析。
      
      Jsoup可以直接解析某个URL地址、HTML文本内容,它提供非常丰富的处理Dom树的API。如果你使用过JQuery,那你一定会非常熟悉。
      
      Jsoup最强大的莫过于它的CSS选择器支持了。比如:document.select("div.content > div#image > ul > li:eq(2)。
      
      包引入方法
      
      Maven
      
      添加下面的依赖声明即可,最新版本是(1.12.1)
      
      
      
      
      
      org.jsoup
      
      jsoup
      
      1.11.3
      
      
      
      Gradle
      
      // jsoup HTML parser library @ https://jsoup.org/
      
      compile ‘org.jsoup:jsoup:1.11.3’
      
      源码安装
      
      当然也可以直接把jar包下载下来,下载地址:https://www.xgjrfwsc.cn jsoup.org/download
      
      # git获取代码
      
      git clone https://www.yifayuLed.cn github.com/jhy/jsoup.git
      
      cd jsoup
      
      mvn install
      
      # 下载代码
      
      curl -Lo jsoup.zip https://github.com/jhy/jsoup/archive/master.zip
      
      unzip jsoup.zip
      
      cd jsoup-master
      
      mvn install
      
      Jsoup解析方法
      
      Jsoup支持四种方式解析Document,即可以输入四种内容得到一个Document:
      
      解析字符串
      
      解析body片段
      
      从一个URL解析
      
      从一个文件解析
      
      字符串解析示例
      
      字符串中必须包含head和body元素。
      
      String html = “First parse
      
      + "

    Parsed HTML into a doc.

    展开全文
  • 一、前言通过前面的文章,我们已经知道了如何获取...因为对于爬虫来讲,正则表达式太复杂对新手十分不友好,而且正则表达式的容错率差,网页有稍微的改动就得重新写匹配表达式,另外正则表达式可读性几乎没有。当然...

    一、前言

    通过前面的文章,我们已经知道了如何获取网页和下载文件,但是前面我们获取的网页都是未经处理的,冗余的信息太多,无法进行分析和利用

    这一节我们就来学习怎么从网页中筛选自己需要的信息

    说到信息筛选我们立马就会想到正则表达式,不过今天我们不讲正则表达式。因为对于爬虫来讲,正则表达式太复杂对新手十分不友好,而且正则表达式的容错率差,网页有稍微的改动就得重新写匹配表达式,另外正则表达式可读性几乎没有。

    当然,这并不是说正则不好,只是正则不适合爬虫和新手。其实正则是十分强大的,在后面的数据清洗里我们会用到正则。

    既然正则不能用,那该用什么呢?别担心,python为我们提供了很多解析 html页面的库,其中常用的有:

    bs4中的 BeautifulSoup

    lxml中的 etree(一个 xpath解析库)

    BeautifulSoup类似 jQuery的选择器,通过 id、css选择器和标签来查找元素,xpath主要通过 html节点的嵌套关系来查找元素,和文件的路径有点像,比如:

    #获取 id为 tab的 table标签下所有 tr标签

    path = '//table[@id="tab"]//tr'

    #和文件路径对比

    path = 'D:\Github\hexo\source\_posts'

    BeautifulSoup和 xpath没有好坏优劣之分,讲 xpath是因为个人觉得 xpath更好用一些,后面如果时间允许的话再讲 BeautifulSoup。

    现在,让我们先从 xpath开始!

    二、xpath的安装和使用

    安装 lxml库

    pip install lxml

    简单的使用

    在使用 xpath之前,先导入 etree类,对原始的 html页面进行处理获得一个_Element对象

    我们可以通过_Element对象来使用 xpath

    #导入 etree类

    from lxml import etree

    #作为示例的 html文本

    html = '''

    点击我

    '''

    #对 html文本进行处理 获得一个_Element对象

    dom = etree.HTML(html)

    #获取 a标签下的文本

    a_text = dom.xpath('//div/div/div/div/div/a/text()')

    print(a_text)

    打印结果:

    091c3aa0a73b

    result-1

    熟悉 html的朋友都知道在 html中所有的标签都是节点。一个 html文档是一个文档节点,一个文档节点包含一个节点树,也叫做 dom树。

    节点树中的节点彼此拥有层级关系。

    父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。

    在节点树中,顶端节点被称为根(root)

    每个节点都有父节点、除了根(它没有父节点)

    一个节点可拥有任意数量的子

    同胞是拥有相同父节点的节点

    另外,我们把距离某个节点最近的子节点叫做它的直接子节点,如下图所示的 body和 head就是 html的直接子节点

    091c3aa0a73b

    dom树 w3school

    了解了 html结构之后我们再来看 xpath的使用。

    首先,我们通过 etree.HTML( )来生成一个_Element对象,etree.HTML() 会将传入的文本处理成一个 html文档节点。这样就能保证我们总是能获得一个包含文档节点的_Element对象。

    xpath语法

    a / b :‘/’在 xpath里表示层级关系,左边的 a是父节点,右边的 b是子节点,这里的 b是 a的直接子节点

    a // b:两个 / 表示选择所有 a节点下的 b节点(可以是直接子节点,也可以不是),在上面的例子中我们要选择 a标签是这样写的

    a_text = dom.xpath('//div/div/div/div/div/a/text()')

    #用 //

    a_text = dom.xpath('//div//a/text()')

    #如果 div标签下有两个 a标签,那么这两个 a标签都会被选择(注意两个 a标签并不一定是兄弟节点)

    #比如下面的例子中的两个 a标签都会被选择 因为这两个 a标签都是 div的子节点

    '''

    点击我

    点击我

    '''

    [@]:选择具有某个属性的节点

    //div[@classs], //a[@x]:选择具有 class属性的 div节点、选择具有 x属性的 a节点

    //div[@class="container"]:选择具有 class属性的值为 container的 div节点

    //a[contains(text(), "点")]:选择文本内容里含有 “点” 的 a标签,比如上面例子中的两个 a标签

    //a[contains(@id, "abc")]:选择 id属性里有 abc的 a标签,如

    #这两条 xpath规则都可以选取到例子中的两个 a标签

    path = '//a[contains(@href, "#123")]'

    path = '//a[contains(@href, "#1233")]'

    //a[contains(@y, "x")]:选择有 y属性且 y属性包含 x值的 a标签

    总结

    使用 xpath之前必须先对 html文档进行处理

    html dom树中所有的对象都是节点,包括文本,所以 text()其实就是获取某个标签下的文本节点

    通过_Element对象的 xpath方法来使用 xpath

    注意!!!_Element.xpath( path) 总是返回一个列表

    有问题欢迎评论

    下一篇实战我们会用 requests和 xpath写一个批量下载壁纸的爬虫

    展开全文
  • jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常好用省事的API,可通过DOM,CSS以及类似于JQuery的操作方法来取出和操作数据。 第一步:工欲善其事必先利其器---使用jsoup需要...

    jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常好用省事的API,可通过DOM,CSS以及类似于JQuery的操作方法来取出和操作数据。

    第一步:工欲善其事必先利其器---使用jsoup需要的四个Jar包:

    <dependency>
        <groupId>org.jsoup</groupId>
        <artifactId>jsoup</artifactId>
        <version>1.8.3</version>
    </dependency>
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.9</version>
    </dependency>

    第二步:

    1.入门程序:打开idea,创建maven工程,创建一个jsoupFirstTest类:

    package Jsoup;
    
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.junit.Test;
    
    import java.net.URL;
    
    public class JsoupFirstTest {
        @Test
        public void testUrl() throws  Exception{
    //        解析url地址,第一个参数是访问的URL、第二个参数是访问时候的超时时间
            Document doc = Jsoup.parse(new URL("http://www.baidu.cn"), 1000);
    //        使用标签选择器,获取title标签中的内容
            String title = doc.getElementsByTag("title").first().text();
            System.out.println(title);
        }
    }
    

    这个时候,你会看到,控制台结果为:

    2.JSoup的几大功能:

    package Jsoup;
    
    import org.apache.commons.io.FileUtils;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.junit.Test;
    
    import java.io.File;
    import java.net.URL;
    
    public class JsoupFirstTest {
        @Test
        public void testUrl() throws  Exception{
    //        解析url地址,第一个参数是访问的URL、第二个参数是访问时候的超时时间
            Document doc = Jsoup.parse(new URL("http://www.baidu.com"), 1000);
    //        使用标签选择器,获取title标签中的内容
            String title = doc.getElementsByTag("title").first().text();
            System.out.println(title);
        }
        @Test
        public void testString()  throws  Exception{
    //        使用工具类读取文件,获取字符串
            String content = FileUtils.readFileToString(new File("请输入文件路径"), "utf8");
    //        解析字符串
            Document doc = Jsoup.parse(content);
            String title = doc.getElementsByTag("title").first().text();
            System.out.println(title);
        }
        @Test
        public void testFile() throws  Exception{
    //        解析文件
            Document doc = Jsoup.parse(new File("请输入文件路径"), "UTF8");
            doc.getElementsByTag("title").first().text();
        }
        @Test
        public void testDOM() throws  Exception{
    //        解析文件,获取Document对象
            Document doc = Jsoup.parse(new File("请输入文件路径"), "utf8");
    //        1.根据id查询元素getElementById
            Element element = doc.getElementById("city");
    //        2.根据标签获取元素getElementByTag
    //        3,根据class获取元素getElementByClass
    //        4.根据属性元素getElementByAttibute
    //        打印元素内容
            System.out.println(element.text());
        }
    }
    
     

     

    展开全文
  • BeautifulSoup官方文档地址 文章目录入门Soup的生成对象树中的四种对象Tag名称属性多值属性NavigableStringBeautifulSoupComment文档对象树的遍历向下走使用标签名称导航.contents 和 .children.descendants.string ...

    BeautifulSoup官方文档地址

    入门

    Soup的生成

    # 导包
    from bs4 import BeautifulSoup
    
    # 传入文件句柄
    with open("index.html") as fp:
        soup = BeautifulSoup(fp, 'html.parser')
    
    # 字符串
    soup = BeautifulSoup("<html>a web page</html>", 'html.parser')
    

    对象树中的四种对象

    BeautifulSoup将复杂的HTML文档转换为复杂的Python对象树
    但只有四种对象我们关心。

    Tag

    这里的标签指的就是 html 或者 xml 里面的标签,如 body、a、h 等等。
    我们关心的是名称属性

    # tag指某一具体标签
    soup.tag
    # 链式访问
    soup.tag1.tag2.tag3
    # 不过只能获取第一个 a 标签(可以使用后面的 find_all获取所有的a标签)
    soup.a
    

    名称

    每个标签都有一个名称,可以通过.name以下方式访问:

    # 名称
    soup.tag.name
    

    属性

    标签可以具有任意数量的属性。
    你可以通过将标签视为字典来访问标签的属性。

    tag = BeautifulSoup('<b id="boldest">bold</b>', 'html.parser').b
    # python的字典访问
    tag['id']
    # 'boldest'
    
    # .attrs返回字典
    tag.attrs
    # {'id': 'boldest'}
    
    # 判断是否拥有某个属性
    tag.has_attr("id")
    

    其实还可以修改它,但这里就不说了。

    多值属性

    有些属性可以有多个值。如class。
    Beautiful Soup将多值属性的值显示为列表。

    css_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html.parser')
    css_soup.p['class']
    # ['body', 'strikeout']
    

    NavigableString

    其实就是在标签里面写的,我们能看到的字符串。

    soup = BeautifulSoup('<b class="boldest">Extremely bold</b>', 'html.parser')
    tag = soup.b
    tag.string
    # 'Extremely bold'
    type(tag.string)
    # <class 'bs4.element.NavigableString'>
    

    BeautifulSoup

    该BeautifulSoup对象代表了整个解析后的文档。对于大多数目的,您可以将其视为Tag 对象。
    如 soup 就是对象树的根部tag。

    Comment

    似乎就是那些注释?maybe
    总之,它不重要。

    文档对象树的遍历

    必须要说的,只有tag才能迭代遍历,string不可以,因为string没有“孩子”。

    向下走

    使用标签名称导航

    就这么简单,直接访问就好。

    # tag指某一具体标签
    soup.tag
    # 链式访问
    soup.tag1.tag2.tag3
    

    .contents 和 .children

    一个标签的孩子列表的获取方法。
    两种方法区别不大。

    print(type(soup.html.children))
    print(type(soup.html.contents))
    
    # <class 'list_iterator'>
    # <class 'list'>
    

    字符串没有.contents。

    .descendants

    递归地获取孩子、孩子的孩子。
    自己测试一下,就知道它的解析逻辑了。

    .string 和 .strings、stripped_strings

    • 如果标签只有一个孩子,而该孩子是一个NavigableString,则该孩子可以使用.string。

    • 使用.strings生成器获取文档中所有的可见字符串。

    • 使用stripped_strings去掉生成的很多的换行。

    向上走

    .parent

    您可以使用.parent属性访问元素的父级。

    .parents

    您可以使用遍历元素的所有父对象 .parents。此示例用于.parents从埋在文档深处的标记移动到文档的最顶部。

    link = soup.a
    link
    # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
    for parent in link.parents:
        print(parent.name)
    # p
    # body
    # html
    # [document]
    

    向一边走

    同一标记的直接子代。我们称他们为兄弟姐妹。

    .next_sibling和.previous_sibling

    要小心,在实际文档中,标签的.next_sibling或.previous_sibling通常通常是包含空格的字符串。

    # <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
    # <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
    # <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
    link = soup.a
    link.next_sibling.next_sibling
    # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
    

    .next_siblings和.previous_siblings

    您可以使用.next_siblings或.previous_siblings遍历标签的同级元素。

    文档对象树的搜索

    对于爬虫者来说,搜索应该让人更感兴趣。

    演示用的html

    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>
    
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    """
    

    过滤器

    过滤器其实就是你指定如何去搜索指定的东西。

    在详细讨论find_all()和类似方法之前,我想展示可以传入这些方法的不同过滤器的示例。这些过滤器会在整个搜索API中一次又一次地显示。您可以使用它们根据标签的名称,属性,字符串文本或它们的某种组合进行过滤。

    字符串

    最简单的过滤器是字符串。将字符串传递给搜索方法,Beautiful Soup将对该字符串进行匹配。此代码查找文档中的所有的b标签

    soup.find_all('b')
    #[<b>The Dormouse's story</b>]
    

    正则表达式

    如果传入正则表达式对象,Beautiful Soup将使用其search()方法针对该正则表达式进行过滤。此代码查找名称以字母“ b”开头的所有标签;在这种情况下,标签和标签:

    import re
    for tag in soup.find_all(re.compile("^b")):
        print(tag.name)
    # body
    # b
    

    此代码查找名称中包含字母“ t”的所有标签:

    for tag in soup.find_all(re.compile("t")):
        print(tag.name)
    # html
    # title
    

    列表

    如果您传递列表,Beautiful Soup将允许对该列表中的任何项目进行字符串匹配(或的关系)。此代码查找所有a标签 和所有b标签。

    soup.find_all(["a", "b"])
    # [<b>The Dormouse's story</b>,
    #  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
    #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    

    True

    该值True匹配所有可能的值。此代码查找文档中的所有标签,忽略到任何文本字符串。

    函数

    你可以传入一个函数,就像一个谓词一样。

    • 函数的参数是Tag
      默认情况下,谓词函数的参数是 tag 对象
    # 只要那些有class属性,而没有id属性的标签,
    def has_class_but_no_id(tag):
        return tag.has_attr('class') and not tag.has_attr('id')
        
    soup.find_all(has_class_but_no_id)
    # [<p class="title"><b>The Dormouse's story</b></p>,
    #  <p class="story">Once upon a time there were…bottom of a well.</p>,
    #  <p class="story">...</p>]
    
    • 函数的参数是Tag的属性
      如果您传入一个函数以过滤特定属性(例如) href,则传递给该函数的参数将是属性值,而不是整个标记。
    import re
    def not_lacie(href):
        return href and not re.compile("lacie").search(href)
    
    soup.find_all(href=not_lacie)
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    

    find_all

    函数原型,返回值

    find_all(name, attrs, recursive, string, limit, **kwargs)
    

    该find_all()方法浏览标签的后代,并检索与过滤器匹配的所有后代。

    举例

    soup.find_all("title")
    # [<title>The Dormouse's story</title>]
    
    soup.find_all("p", "title")
    # [<p class="title"><b>The Dormouse's story</b></p>]
    
    soup.find_all("a")
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
    #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    
    soup.find_all(id="link2")
    # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
    
    import re
    soup.find(string=re.compile("sisters"))
    # 'Once upon a time there were three little sisters; and their names were\n'
    

    下面函数的参数做出解释。

    因为它find_all()是Beautiful Soup搜索API中最受欢迎的方法,所以可以为其使用快捷方式。如果将 BeautifulSoup对象或Tag对象视为函数,则与调用find_all()该对象相同。这两行代码是等效的:

    # 这也是等效的
    soup.find_all("a")
    soup("a")
    # 这也是等效的
    soup.title.find_all(string=True)
    soup.title(string=True)
    

    name

    只考虑标签的名字进行搜索,忽略属性、可见字符串

    soup.find_all("title")
    # [<title>The Dormouse's story</title>]
    

    attrs

    # 可以直接指定
    soup.find_all(id='xxx')
    # 同时指定多个:
    soup.find_all(id='xxx',href=href_filter);
    # 通过字典传入
    soup.find_all(attrs = {'id' : 'xxx', 'name':'form_name'})
    
    • CSS class
      如果是对于class属性的话,即可以使用attrs传入。
    soup.find_all("a", attrs={"class": "sister"})
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
    #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    

    不过还有更简洁的做法:
    使用class_

    css_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html.parser')
    css_soup.find_all("p", class_="strikeout")
    # [<p class="body strikeout"></p>]
    
    css_soup.find_all("p", class_="body")
    # [<p class="body strikeout"></p>]
    

    string

    根据 可见字符串 进行匹配。
    与 name和参数关键字一样,您可以传入字符串,正则表达式,列表,函数或值True。

    soup.find_all(string = "Elsie")
    # ['Elsie']
    

    注意这时返回的是匹配的字符串列表
    如果你要根据string匹配并且返回tag列表,你必须显式加上name

    soup.find_all(name = True,string = "Elsie")
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
    

    limit

    find_all()返回与您的过滤器匹配的所有标记和字符串。如果文档较大,则可能需要一段时间。如果您不需要所有结果,可以输入的数字limit。就像SQL中的LIMIT关键字一样工作。它告诉Beautiful Soup在找到一定数量后停止收集结果。

    soup.find_all("a", limit=2)
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
    

    recursive

    您只希望soup考虑直接的孩子,则可以传递recursive=False
    默认是True。

    find家族

    除了前面长篇大论说的 find_all,
    还有其他很实用的find方法。

    find()

    相当于设置find_all的limit为1 ;
    唯一的区别是,find_all()返回包含单个结果的列表,而find()仅返回结果。
    如果find_all()找不到任何内容,则返回一个空列表。如果 find()找不到任何内容,则返回None。

    find_parents()和find_parent()

    前面的 find find_all都是往”后代找“。

    find_parents()和find_parent()是往树上面找。
    看函数的名字就知道,一个一直往上搜索,另一个仅仅直系parent。

    find_next_siblings()和find_next_sibling()

    这些方法使用.next_siblings遍历树中元素的其余同级。该 find_next_siblings()方法返回所有匹配的兄弟姐妹,并且find_next_sibling()仅返回第一个。

    find_previous_siblings()和find_previous_sibling()

    这些方法使用.previous_siblings遍历树中位于其之前的元素的同级元素。该find_previous_siblings() 方法返回所有匹配的兄弟姐妹,并且 find_previous_sibling()仅返回第一个。

    find_all_next()和find_next()

    这些方法使用.next_elements遍历文档中紧随其后的所有标签和字符串。该find_all_next()方法返回所有匹配项,并且 find_next()仅返回第一个匹配项。

    find_all_previous()和find_previous()

    这些方法使用.previous_elements遍历文档中位于其之前的标签和字符串。该find_all_previous()方法返回所有匹配项,并且 find_previous()仅返回第一个匹配项。

    CSS选择器

    css选择器介绍

    • 通过CSS类查找标签
    soup.select(".sister")
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
    #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    
    soup.select("[class~=sister]")
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
    #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    
    • 按ID查找标签
    soup.select("#link1")
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
    
    soup.select("a#link2")
    # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
    
    • 测试属性的存在
    soup.select('a[href]')
    # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
    #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    
    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,562
精华内容 2,224
关键字:

爬虫html解析

爬虫 订阅