1、4.2 scrapy中查找中查找HTML元素元素(1)在前面我们已经知道使用BeautifulSoup能查找HTML中的元素,scrapy中也有强大的查找HTML元素的功能,那就是使用xpath方法。xpath方法使用XPath语法,比BeautifulSoup的select要灵活而且速度快。例例4-2-1:使用使用xpath查找查找HTML中的元素中的元素fromscrapy.selectorimportSelectorhtmlText=HarryPotter29.99LearningXML39.95selector=Selector(text=htmlText)print(type(sel
2、ector);print(selector)s=selector.xpath(/title)print(type(s)print(s)程序结果:classscrapy.selector.unified.SelectorSelectorxpath=Nonedata=nnnSelectorxpath=/titledata=HarryPotter,Selectorxpath=/titledata=LearningXML(1)fromscrapy.selectorimportSelector从scrapy中引入Selector类,这个类就是选择查找类。(2)selector=Selector(text
3、=htmlText)使用htmlText的文字建立Selector类,就是装载HTML文档,文档装载后就形成一个Selector对象,就可以使用xpath查找元素。(3)print(type(selector)可看到selector是一个类型为scrapy.selector.unified.Selector,这个类型是一个有xpath方法的类型。(4)s=selector.xpath(/title)这个方法在文档中查找所有的的元素,其中/表示文档中的任何位置。一般地:selector.xpath(/tagName)表示在权文档中搜索的tags,形成一个Selector的列表。(5)print(
4、type(s)由于有两个元素,因此我们看到这是一个scrapy.selector.unified.SelectorList类,类似scrapy.selector.unified.Selector的列表。(6)print(s)我们看到s包含两个Selector对象,一个是Selectorxpath=/titledata=HarryPotter,另外一个是Selectorxpath=/titledata=LearningXML。Selectorxpath=/titledata=LearningXML由此可见一般selector搜索一个的HTML元素的方法是:selector.xpath(/tagN
5、ame)在装载HTML文档后selector=Selector(text=htmlText)得到的selector是对应全文档顶层的元素的,其中/表示全文档搜索,结果是一个Selector的列表,哪怕只有一个元素也成一个列表,例如:selector.xpath(/body)搜索到元素,结果是一个Selector的列表,包含一个Selector元素;selector.xpath(/title)搜索到两个元素,结果是Selector的列表,包含2个Selector元素;selector.xpath(/book)搜索到两个元素,结果是Selector的列表,包含2个Selector元素;4.2 sc
6、rapy中查找中查找HTML元素元素(2)1、使用、使用/表示文档下面的所有节点元素,用表示文档下面的所有节点元素,用/表示当前节点的下一级节点元素。表示当前节点的下一级节点元素。例例4-2-2:/与与/的使用的使用selector.xpath(/bookstore/book)搜索下一级的元素,找到2个;selector.xpath(/body/book)搜索下一级的元素,结果为空;selector.xpath(/body/book)搜索下元素,找到2个;selector.xpath(/body/book)搜索文档下一级的下的元素,找结果为空,因为文档的下一级是元素,不是元素;selector
7、.xpath(/html/body/book)或者selector.xpath(/html/book)搜索元素,找到2个;selector.xpah(/book/title)搜索文档中所有下一级的元素,找到2个,结果与selector.xpah(/title)、selector.xpath(/bookstore/title)一样;selector.xpath(/book/price)与selector.xpath(/price)结果一样,都是找到2个元素;2、使用、使用.表示当前节点元素,使用表示当前节点元素,使用xpath可以连续调用,如果前一个可以连续调用,如果前一个xpath返回一个返回
8、一个Selector的列表,那么这个列表可以继续调用的列表,那么这个列表可以继续调用xpath,功能是为每个列表,功能是为每个列表元素调用元素调用xpath,最后结果是全部元素调用,最后结果是全部元素调用xpath的汇总。的汇总。例例4-2-3:使用:使用.进行进行xpath连续调用连续调用fromscrapy.selectorimportSelectorhtmlText=booksNovelHarryPotter29.99TextBookLearningXML39.95selector=Selector(text=htmlText)s=selector.xpath(/book).xpath(
9、./title)foreins:print(e)程序结果:Selectorxpath=/book/titledata=NovelSelectorxpath=/book/titledata=HarryPotterSelectorxpath=/book/titledata=TextBookSelectorxpath=/book/titledata=LearningXML我们看到selector.xpath(/book)首先搜索到文档中所有元素,总共有2个,然后再次调用xpath(./title),就是从当前元素开始往下一级搜索,每个都找到2个,因此结果有4个。注意如果xpath连续调用时不指定是从
10、前一个xpath的结果元素开始的,那么默认是从全文档开始的,结果会不一样,例如:s=selector.xpath(/book).xpath(/title)结果是空的,因为后面的xpath(/title)从文档开始搜索。s=selector.xpath(/book).xpath(/title)结果有10个元素,因为每个都驱动xpath(/title)在全文档搜索元素,每次都搜索到5个元素。4.2 scrapy中查找中查找HTML元素元素(3)3、如果、如果xpath返回的返回的Selector对象列表,再次调用对象列表,再次调用extract()函数会得到这些对函数会得到这些对象的元素文本的列表
11、,使用象的元素文本的列表,使用extract_first()获取列表中第一个元素值,如果列获取列表中第一个元素值,如果列表为空表为空extract_first()的值为的值为None。而对于单一的一个而对于单一的一个Selector对象,调用对象,调用extract()函数就可以得到函数就可以得到Selector对象对象对应的元素的文本值。单一的对应的元素的文本值。单一的Selector对象没有对象没有extract_first()函数。函数。例例4-2-4:extract与与extract_first函数使用函数使用fromscrapy.selectorimportSelectorhtmlT
12、ext=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/book/price)print(type(s),s)s=selector.xpath(/book/price).extract()print(type(s),s)s=selector.xpath(/book/price).extract_first()print(type(s),s)程序结果:Selectorxpath=/book/pricedata=29.99,Selectorxpath=/book/pricedata=39.952
13、9.99,39.9529.99由此可见:s=selector.xpath(/book/price)得到的是SelectorList列表;s=selector.xpath(/book/price).extract()得到的是元素的Selector对象对应的元素的文本组成的列表,即:29.99,39.95s=selector.xpath(/book/price).extrac_first()得到的是元素的文本组成的列表的第一个元素,是一个文本,即:29.994、xpath使用使用/attrName得到一个得到一个Selector元素的元素的attrName属性节点对象,属性节点对象也是一个属性节点
14、对象,属性节点对象也是一个Selector对象,通过对象,通过extract()获取属性获取属性值。值。例例4-2-5:获取元素属性值:获取元素属性值htmlText=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/book/id)print(s)print(s.extract()foreins:print(e.extract()程序结果:,b1,b2b1b2由此可见:s=selector.xpath(/book/id)结果是2个的id属性组成的SelectorList列表,即属性也是一个S
15、elector对象;print(s.extract()结果是的id属性的两个Selector对象的属性文本值的列表,即b1,b2;foreins:print(e.extract()每个e是一个Selector对象,因此extract()获取对象的属性值。4.2 scrapy中查找中查找HTML元素元素(4)5、xpath使用使用/text()得到一个得到一个Selector元素包含的文本值,文本值节点对象也是一个元素包含的文本值,文本值节点对象也是一个Selector对象,通过对象,通过extract()获取文本值。获取文本值。例:例:4-2-6:获取节点的文本值:获取节点的文本值fromsc
16、rapy.selectorimportSelectorhtmlText=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/book/title/text()print(s)print(s.extract()foreins:print(e.extract()程序结果:,HarryPotter,学习XMLHarryPotter学习XML由此可见:s=selector.xpath(/book/title/text()结果也是SelectorList列表,即文本也是一个节点;print(s.extra
17、ct()结果是文本节点的字符串值的列表,即HarryPotter,学习XML;foreins:print(e.extract()每个e是一个Selector对象,因此extract()获取对象的属性值。值得注意的是如果一个element的元素包含的文本不是单一的文本,那么可能会产生多个文本值。例例4-2-7:多个文本节点值多个文本节点值fromscrapy.selectorimportSelectorhtmlText=HarryPotter29.99selector=Selector(text=htmlText)s=selector.xpath(/book/title/text()print(
18、s)print(s.extract()foreins:print(e.extract()程序结果:,arry,otterarryotter由此可见title中的文本值包含arry与otter两个。6、xpath使用使用tagcondition来限定一个来限定一个tag元素,其中元素,其中condition是由这个是由这个tag的属性、文本等计算出的一个逻辑值。如果有多个条件,那么可以写成:的属性、文本等计算出的一个逻辑值。如果有多个条件,那么可以写成:tagcondition1condition2.conditionN或者:或者:tagcondition1 and condition2 and
19、.and conditionN 例例4-2-8:使用:使用condition限定限定tag元素元素fromscrapy.selectorimportSelectorhtmlText=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/book/titlelang=chinese/text()print(s.extract_first()s=selector.xpath(/bookid=b1/title)print(s.extract_first()程序结果:学习XMLHarryPotter由此可
20、见:s=selector.xpath(/book/titlelang=chinese/text()搜索下面属性lang=chinese的s=selector.xpath(/bookid=b1/title)搜索属性id=b1的下面的。4.2 scrapy中查找中查找HTML元素元素(5)7、xpath可以使用可以使用position()来确定其中一个元素的限制,这个选择序号是从来确定其中一个元素的限制,这个选择序号是从1开始的,不是从开始的,不是从0开始编号的,还可以通过开始编号的,还可以通过 and、or等构造复杂等构造复杂的表达式。的表达式。例例4-2-9:使用:使用position()序号
21、来确定锁选择的元素序号来确定锁选择的元素fromscrapy.selectorimportSelectorhtmlText=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/bookposition()=1/title)print(s.extract_first()s=selector.xpath(/bookposition()=2/title)print(s.extract_first()程序结果:HarryPotter学习XML其中:s=selector.xpath(/bookpositi
22、on()=1/title)s=selector.xpath(/bookposition()=1/title)分别选择第一、二个元素。8、xpath使用星号使用星号*代表任何代表任何Element节点,不包括节点,不包括Text、Comment的节点。的节点。例例4-2-10:使用使用*代表任何代表任何element元素元素fromscrapy.selectorimportSelectorhtmlText=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/bookstore/*/title)pr
23、int(s.extract()程序结果:HarryPotter,学习XML其中s=selector.xpath(/bookstore/*/title)是搜索的孙子节点,中间隔开一层任何元素。4.2 scrapy中查找中查找HTML元素元素(6)9、xpath使用使用*代表任何属性代表任何属性例例4-2-11:使用:使用*代表属性代表属性fromscrapy.selectorimportSelectorhtmlText=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/book*/title)p
24、rint(s.extract()s=selector.xpath(/*)print(s.extract()程序结果:学习XMLenglish,b2,chinese其中:s=selector.xpath(/book*/title)是搜索任何包含属性的元素下面的,结果搜索到第二个s=selector.xpath(/*)是搜索文档中所有属性节点。10、xpath使用使用element/parent:*选择选择element的父节点,这个节点只有一的父节点,这个节点只有一个。如果写成个。如果写成element/parent:tag,就指定,就指定element的的tag父节点,除非父节点,除非elem
25、ent的父节点正好为的父节点正好为节点,不然就为节点,不然就为None。例例4-2-12:xpath搜索元素的父节点搜索元素的父节点fromscrapy.selectorimportSelectorhtmlText=HarryPotter29.99学习XML39.95selector=Selector(text=htmlText)s=selector.xpath(/titlelang=chinese/parent:*)print(s.extract()程序结果:n学习XMLn39.95n其中s=selector.xpath(/titlelang=chinese/parent:*)是查找属性为l
26、ang=chinese的元素的父节点,就是id=b2的元素节点。4.2 scrapy中查找中查找HTML元素元素(7)11、xpath使用使用element/folllowing-sibling:*搜索搜索element后面的同级的所后面的同级的所有兄弟节点,使用有兄弟节点,使用element/folllowing-sibling:*position()=1 搜索搜索element后面的同级的第一个兄弟节点。后面的同级的第一个兄弟节点。例例4-2-13:搜索后面的兄弟节点搜索后面的兄弟节点fromscrapy.selectorimportSelectorhtmlText=A1B1C1DEB2C
27、2selector=Selector(text=htmlText)s=selector.xpath(/a/following-sibling:*)print(s.extract()s=selector.xpath(/a/following-sibling:*position()=1)print(s.extract()s=selector.xpath(/bposition()=1/following-sibling:*)print(s.extract()s=selector.xpath(/bposition()=1/following-sibling:*position()=1)print(s.
28、extract()程序结果:B1,C1,DE,B2,C2B1C1,DE,B2,C2C1例如:s=selector.xpath(/bposition()=1/following-sibling:*position()=1)是搜索第一个节点后面的第一个兄弟节点,即C1节点。12、xpath使用使用element/preceding-sibling:*搜索搜索element前面的同级的所前面的同级的所有兄弟节点,使用有兄弟节点,使用element/preceding-sibling:*position()=1 搜索搜索element前面的同级的第一个兄弟节点。前面的同级的第一个兄弟节点。例例4-2-
29、14:搜索前面的兄弟节点搜索前面的兄弟节点fromscrapy.selectorimportSelectorhtmlText=A1B1C1DEB2C2selector=Selector(text=htmlText)s=selector.xpath(/a/preceding-sibling:*)print(s.extract()s=selector.xpath(/b/preceding-sibling:*position()=1)print(s.extract()s=selector.xpath(/bposition()=2/preceding-sibling:*)print(s.extract()s=selector.xpath(/bposition()=2/preceding-sibling:*position()=1)print(s.extract()程序结果:A1,DEA1,B1,C1,DEDE例如:s=selector.xpath(/b/preceding-sibling:*position()=1)是所有前面的第一个兄弟节点,因为有2个节点,因此结果是A1,DE