2

如果这是一个重复的问题,我深表歉意,但我在 SO 或其他似乎可以处理我需要的问题上找不到另一个问题。这是我的问题:

我用来从这个网页scrapy中获取一些信息。为清楚起见,以下是我感兴趣的该网页的源代码块:

<p class="titlestyle">ANT101H5 Introduction to Biological Anthropology and Archaeology 
                        <span class='distribution'>(SCI)</span></p> 

<span class='normaltext'> 
Anthropology is the global and holistic study of human biology and behaviour, and includes four subfields: biological anthropology, archaeology, sociocultural anthropology and linguistics. The material covered is  directed  to answering the question: What makes us human? This course is a survey of  biological  anthropology and  archaeology.  [<span class='Helpcourse'
            onMouseover="showtip(this,event,'24 Lectures')"
            onMouseout="hidetip()">24L</span>, <span class='Helpcourse'
            onMouseover="showtip(this,event,'12 Tutorials')"
            onMouseout="hidetip()">12T</span>]<br> 

<span class='title2'>Exclusion: </span><a href='javascript:OpenCourse("WEBCOURSENOTFOUND.html")'>ANT100Y5</a><br>

<span class='title2'>Prerequisite: </span><a href='javascript:OpenCourse("WEBCOURSEANT102H5.pl?fv=1")'>ANT102H5</a><br> 
</span><br/><br/<br/> 

该页面上的几乎所有代码都类似于上面的代码块。

从所有这些中,我需要抓住:

  1. ANT101H5 生物人类学和考古学概论
  2. 排除:ANT100Y5
  3. 先决条件:ANT102H5

问题是它Exclusion:在 a里面<span class="title2">并且ANT100Y5在下面的里面<a>

我似乎无法从这个源代码中获取它们。目前,我有尝试(并且失败)抓取的代码,ANT100Y5如下所示:

hxs = HtmlXPathSelector(response)
    sites = hxs.select("//*[(name() = 'p' and @class = 'titlestyle') or (name() = 'a' and @href and preceding-sibling::'//span/@class=title2')]")

我将不胜感激任何帮助,即使它是“你因为没有看到另一个完美回答这个问题的 SO 问题而失明”(在这种情况下,我自己将投票关闭这个问题)。我真的很无能为力。

提前致谢

编辑:@Dimitre 建议的更改后完成原始代码

我正在使用以下代码:

class regcalSpider(BaseSpider):
    name = "disc"
    allowed_domains = ['www.utm.utoronto.ca']
    start_urls = ['http://www.utm.utoronto.ca/regcal/WEBLISTCOURSES1.html']

    def parse(self, response):
            items = []
            hxs = HtmlXPathSelector(response)
            sites = hxs.select("/*/p/text()[1] | \
                              (//span[@class='title2'])[1]/text() | \
                              (//span[@class='title2'])[1]/following-sibling::a[1]/text() | \
                              (//span[@class='title2'])[2]/text() | \
                              (//span[@class='title2'])[2]/following-sibling::a[1]/text()")

            for site in sites:
                    item = RegcalItem()
                    item['title'] = site.select("a/text()").extract()
                    item['link'] = site.select("a/@href").extract()
                    item['desc'] = site.select("text()").extract()
                    items.append(item)
            return items

            filename = response.url.split("/")[-2]
            open(filename, 'wb').write(response.body)

这给了我这个结果:

[{"title": [], "link": [], "desc": []},
 {"title": [], "link": [], "desc": []},
 {"title": [], "link": [], "desc": []}]

这不是我需要的输出。我究竟做错了什么?请记住,如前所述,我在 this 上运行此脚本

4

3 回答 3

3

.1。ANT101H5 生物人类学和考古学概论

p[@class='titlestyle']/text()

.2. 排除:ANT100Y5

concat(
    span/span[@class='title2'][1],
    span/span[@class='title2'][1]/following-sibling::a[1]
    )

.3. 先决条件:ANT102H5

concat(
    span/span[@class='title2'][2],
    span/span[@class='title2'][2]/following-sibling::a[1]
    )
于 2011-03-05T08:41:52.173 回答
2

选择您引用的三个节点并不难(使用 Flack 等技术)。困难的是(a)选择它们而不选择其他您不想要的东西,以及(b)使您的选择足够健壮,即使输入略有不同,它仍然会选择它们。我们必须假设您不确切知道输入中的内容 - 如果您知道,则不需要编写 XPath 表达式来查找。

你已经告诉我们你想要抓住的三件事。但是,您选择这三样东西而不选择其他东西的标准是什么?对您正在寻找的内容了解多少?

您已将您的问题表达为 XPath 问题,但我会以不同的方式处理它。我将首先使用 XSLT 将您显示的输入转换为具有更好结构的内容。特别是,我会尝试将不在一个<p>元素内的所有兄弟元素包装成<p>元素,将每组以结尾的连续元素<br>视为一个段落。<xsl:for-each-group group-ending-with>使用XSLT 2.0 中的结构可以毫不费力地做到这一点。

于 2011-03-05T18:07:00.460 回答
1

我的回答很像@Flack 的回答

拥有这个 XML 文档(更正了提供的一个关闭多个未关闭<br>的 s 并将所有内容包装在单个顶部元素中的内容):

<body>
    <p class="titlestyle">ANT101H5 Introduction to Biological Anthropology and Archaeology 
        <span class='distribution'>(SCI)</span>
    </p>
    <span class='normaltext'> Anthropology is the global and holistic study of human biology and behaviour, and includes four subfields: biological anthropology, archaeology, sociocultural anthropology and linguistics. The material covered is directed to answering the question: What makes us human? This course is a survey of biological anthropology and archaeology. [
        <span class='Helpcourse' onMouseover="showtip(this,event,'24 Lectures')" onMouseout="hidetip()">24L</span>, 
        <span class='Helpcourse' onMouseover="showtip(this,event,'12 Tutorials')" onMouseout="hidetip()">12T</span>]
        <br/>
        <span class='title2'>Exclusion: </span>
        <a href='javascript:OpenCourse("WEBCOURSENOTFOUND.html")'>ANT100Y5</a>
        <br/>
        <span class='title2'>Prerequisite: </span>
        <a href='javascript:OpenCourse("WEBCOURSEANT102H5.pl?fv=1")'>ANT102H5</a>
        <br/>
    </span>
    <br/>
    <br/>
    <br/>
</body>

这个 XPath 表达式

normalize-space(/*/p/text()[1])

当评估产生想要的字符串(周围的引号不在结果中。我添加它们以显示产生的确切字符串):

"ANT101H5 Introduction to Biological Anthropology and Archaeology"

这个 XPath 表达式

concat((//span[@class='title2'])[1],
            (//span[@class='title2'])[1]
                   /following-sibling::a[1]
            )

评估时会产生以下想要的结果:

"Exclusion: ANT100Y5"

这个 XPath 表达式

concat((//span[@class='title2'])[2],
            (//span[@class='title2'])[2]
                   /following-sibling::a[1]
            )

评估时会产生以下想要的结果:

"Prerequisite: ANT102H5"

注意:在这种特殊情况下,//不需要缩写,实际上应该尽可能避免使用这种缩写,因为它会导致表达式的计算速度变慢,在许多情况下会导致完整的(子)树遍历。我故意使用'//',因为提供的XML 片段没有给我们XML 文档的完整结构。此外,这演示了如何正确索引 using 的结果//(注意周围的括号) - 有助于防止在尝试这样做时出现非常频繁的错误

更新:OP 请求了一个 XPath 表达式来选择所有需要的文本节点——这里是:

/*/p/text()[1]
   |
    (//span[@class='title2'])[1]/text()
   |
    (//span[@class='title2'])[1]/following-sibling::a[1]/text()
   |
    (//span[@class='title2'])[2]/text()
   |
    (//span[@class='title2'])[2]/following-sibling::a[1]/text()

当应用于与上述相同的 XML 文档时,文本节点的连接正是所需要的:

ANT101H5 Introduction to Biological Anthropology and Archaeology          
        Exclusion: ANT100Y5Prerequisite: ANT102H5

可以通过运行以下 XSLT 转换来确认此结果:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:copy-of select=
   "/*/p/text()[1]
   |
    (//span[@class='title2'])[1]/text()
   |
    (//span[@class='title2'])[1]/following-sibling::a[1]/text()
   |
    (//span[@class='title2'])[2]/text()
   |
    (//span[@class='title2'])[2]/following-sibling::a[1]/text()
   "/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于同一个 XML 文档(之前在此答案中指定)时,会产生所需的正确结果

ANT101H5 Introduction to Biological Anthropology and Archaeology          
        Exclusion: ANT100Y5Prerequisite: ANT102H5

最后:下面的单个 XPath 表达式准确地选择了 HTML 页面中所有想要的文本节点,以及提供的链接(在将其整理成格式良好的 XML 之后):

  (//p[@class='titlestyle'])[2]/text()[1]
|
  (//span[@class='title2'])[2]/text()
|
  (//span[@class='title2'])[2]/following-sibling::a[1]/text()
|
  (//span[@class='title2'])[3]/text()
|
  (//span[@class='title2'])[3]/following-sibling::a[1]/text()
于 2011-03-05T16:46:24.477 回答