目录
1.HTML基础知识
什么是HTML?HTML就是前面我们所看到的,从网页上爬取得到的网页源代码,是一种结构化的标记语言。HTML可以描述一个网页的结构信息。
HTML与CSS(Cascading Style Sheets,层叠样式表)、JavaScript一起构成了现代互联网的基石。
2.HTML的标签和属性
2.1标签
在HTML中,这叫作标签。一个标签可以表示为:
<标签名>
文本
</标签名>
1.不加斜杠,表示标签开始;加上斜杠,表示标签结束。
2.它们中间的部分,就是标签里面的元素。
3.标签里面可以是另一个标签,也可以是一段文本。
4.标签可以并列,也可以嵌套。
一段HTML代码实例:
2.2属性
在真实的HTML代码里面,每个标签除了标签名以外,还有“属性”。
一个标签可以有0个、1个或者多个属性:
<标签名 属性1="属性1的值" 属性2="属性2的值">显示在网页上的文本</标签名>
2.3HTML的树形结构层级关系
层层嵌套,通过这样的树形结构,爬虫可以轻松地找到我我们想要的准确信息。
3.XPath
3.1什么是XPath
XPath(XML Path)是一种查询语言,它能在XML(Extensible Markup Language,可扩展标记语言)和HTML的树状结构中寻找结点。
XPath就是一种根据“地址”来“找人”的语言。
与正则表达式相比,用正则表达式来提取信息,经常会出现不明原因的无法提取想要内容的情况。而XPath却不一样,熟练使用XPath以后,构造不同的XPath,所需要花费的时间几乎是一样的,所以用XPath从HTML源代码中提取信息可以大大提高效率。
3.2XPath语法
使用XPath需要安装第三方库lxml。在PyCharm中直接用packages装就ok。
XPath的核心思想:写XPath就是写地址。
通用方法模板:
获取文本://标签1[@属性1="属性值1"]/标签2[@属性2="属性值2"]/..../text()
获取属性值://标签1[@属性1="属性值1"]/标签2[@属性2="属性值2"]/..../@属性n
其中,[@属性="属性值"]不是必需的。它的作用是帮助过滤相同的标签。在不需要过滤相同标签的情况下可以省略。
3.3标签的选取
找标签的原理:不需要从头开始找,也不能找混杂了有效/无效信息的标签。
因此,我们需要“倒着找”。也就是,从需要提取的内容往上找标签,找到一个拥有“标志性属性值”的标签为止。
例如,在2.1中,需要的信息所在的标签为<li class="info">,这个标签的class属性的值为“info”。那能不能用它来定位呢?答案是不能,因为在代码里,虽然需要的内容是使用这个标签包起来的,但是不需要的内容也是使用这个标签包起来的。这就说明这个标签的属性值不够独特,不能称为“拥有标志性属性值的标签”。继续往上找,发现<div class="useful">,这个标签很独特。它的class属性的值“useful”独一无二,而且需要提取的内容又都在这个<div>标签里面。所以这个标签可以称得上是“拥有标志性属性值的标签”,可以从这个标签开始来定位。于是定位的XPath就可以写成:
//div[@class="useful"]/ul/li/text()
3.4省略属性
下列代码片段中,<ul>标签本身就没有属性,则写XPath的时候,其属性可以省略。
标签有属性,但是如果这个标签的所有属性值都相同,则可以省略属性,例如<li class="info">,所有的<li>标签都有一个class属性,值都为info,所以属性可以省略。
3.5应对XPath的一些特殊情况
1.HTML中有相同的字符开头
HTML代码:
html1 = ''' <! DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="test-1">需要的内容1</div> <div id="test-2">需要的内容2</div> <div id="testfault">需要的内容3</div> <div id="useless">这是我不需要的内容</div> </body> </html> '''
XPath方法:
selector = lxml.html.fromstring(html1) content = selector.xpath('//div[starts-with(@id, "test")]/text()')
2.HTML中有属性值包含相同字符
寻找属性值包含某些字符串的元素时,XPath的写法格式和以某些字符串开头的写法格式是相同的,只不过关键字从“starts-with”变成了“contains”。
lxml中的XPath不支持直接提取属性值以某些字符串结尾的情况。如果遇到这种情况,建议使用contains代替。
HTML代码:
html1 = '''' <! DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="abc-key-1">需要的内容1</div> <div id="123-key-2">需要的内容2</div> <div id="haha-key-hh">需要的内容3</div> <div id="useless">这是我不需要的内容</div> </body> </html> '''
XPath方法:
selector = lxml.html.fromstring(html1) content = selector.xpath('//div[contains(@id, "key")]/text()')
3.HTML中先抓大再抓小
可以先抓取useful标签,再对这个标签进一步执行XPath,获取里面子标签的文字。需要注意的是,在对XPath返回的对象再次执行XPath的时候,子XPath开头不需要添加斜线,直接以标签名开始即可。
HTML代码:
source = ''' <html> <head> <title>测试</title> </head> <body> <div class="useful"> <ul> <li class="info">我需要的信息1</li> <li class="info">我需要的信息2</li> <li class="info">我需要的信息3</li> </ul> </div> <div class = "useless"> <ul> <li class = "info">垃圾1</li> <li class = "info">垃圾2</li> </ul> </div> </body> </html> '''
XPath方法:
selector = lxml.html.fromstring(source) useful = selector.xpath('//div[@class = "useful"]') info_list = useful[0].xpath('ul/li/text()') useless = selector.xpath('//div[@class = "useless"]') useless_list = useless[0].xpath('ul/li/text()')
4.HTML中抓取不同标签下的文字
XPath并不会自动把子标签的文字提取出来。在这种情况下,就需要使用string(.)关键字。
HTML代码:
html1 = ''' <! DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="test3"> 我左青龙, <span id="tiger"> 右白虎, <ul>上朱雀, <li>下玄武。</li> </ul> 老牛在当中, </span> 龙头在胸口。 </div> </body> </html> '''
XPath方法:
selector = lxml.html.fromstring(html1) data = selector.xpath('//div[@id = "test3"]')[0] info = data.xpath('string(.)')
4.使用Google Chrome浏览器辅助构造XPath
在构造XPath语句的过程中,需要寻找“标志性”的标签。但是如果遇到图5-12这样混乱的源代码,就不能单纯靠眼睛来看了。
借助Google Chrome浏览器来协助分析网页结构,可以大大提高分析效率。Google Chrome自带的开发者工具可以将网页源代码转换为树状结构,大大提高网页的可读性。
1.在网页上单击右键,在弹出的快捷菜单中选择“检查”命令。
2.打开开发者工具。使鼠标指针在开发者窗口中的HTML代码中移动,可以看到页面上不同的地方会高亮,说明当前鼠标指针指向的这个标签,就对应了网页中高亮的这一部分的代码。
3.除了根据代码找网页位置,还可以根据网页位置找代码。