如果这是一个重复的问题,我道歉,但我无法在SO或其他地方找到另一个似乎能够处理我需要的问题。这是我的问题:
我正在使用scrapy
从this网页中获取一些信息。为清楚起见,以下是该网页的源代码块,我感兴趣的是:
<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/>
该页面上的几乎所有代码都与上面的代码类似。
从这一切开始,我需要抓住:
问题是Exclusion:
位于<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')]")
我很感激任何对此的帮助,即使它是“你因为没有看到这个完全回答这个问题的其他问题而失明”(在这种情况下,我自己会投票决定关闭这个)。在我的智慧结束时,我真的很喜欢。
提前致谢
编辑:在@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上运行此脚本,如上所述。
答案 0 :(得分:3)
0.1。 ANT101H5生物人类学和考古学导论
p[@class='titlestyle']/text()
0.2。排除:ANT100Y5
concat(
span/span[@class='title2'][1],
span/span[@class='title2'][1]/following-sibling::a[1]
)
0.3。先修课程:ANT102H5
concat(
span/span[@class='title2'][2],
span/span[@class='title2'][2]/following-sibling::a[1]
)
答案 1 :(得分:2)
选择你引用的三个节点并不困难(使用Flack等技术)。困难的是(a)选择它们而不选择其他你不想要的东西,以及(b)使你的选择足够强大,如果输入略有不同,它仍然会选择它们。我们必须假设您不确切知道输入中的内容 - 如果您这样做,则不需要编写XPath表达式来查找。
你已经告诉我们你要抓住的三件事。但是你选择这三件事的标准是什么,而不是选择别的东西呢?关于你在寻找什么知道多少?
您已将问题表达为XPath问题,但我会以不同的方式解决它。我将首先使用XSLT将您显示的输入转换为具有更好结构的内容。特别是,我会尝试将不在<p>
元素内的所有兄弟元素包装到<p>
元素中,将每个以<br>
结尾的连续元素组作为段落处理。使用XSLT 2.0中的<xsl:for-each-group group-ending-with>
构造可以毫不费力地完成。
答案 2 :(得分:1)
我的答案与@Flack 的答案非常相似:
拥有这个XML文档(更正提供的文档以关闭众多未关闭的<br>
并将所有内容包装在单个顶部元素中):
<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文档的完整结构。此外,这演示了如何正确索引使用//
的结果(注意周围的括号) - 有助于防止在尝试这样做时经常出现错误
UPDATE :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表达式使用提供的链接(在将其整理成格式良好的XML之后)精确选择HTML页面中所有想要的文本节点:
(//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()