Lxml库、Xpath语法与爬虫
1.认识HTML结构
2.XPath
3.实例:爬取起点中文网的全部作品信息
1.认识HTML结构
html标签组成是html文档的最基本元素,一般是成对出现,由开始标签和与其对应的结束标签构成. 如,
由于html语言是一门弱类型语言,对格式的要求不是非常严格,因此所有标签是不区分大小写的,但是,一般在实际开发中,大家都统一使用小写。
<html >
<head>
<meta charset="utf-8" > <!--网页编码声明-->
<title>标题</title>
<meta name="keywords" content="关键字" />
<meta name="description" content="网页描述" />
</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>
</ul>
</div>
</body>
</html>
HTML结构标记可以参考:https://www.jianshu.com/p/e686c6c01458
2.XPath
XPath是一种查询语言,根据“地址“来”找人“的语言,但需要安装一个第三方库:lxml。
(1)lxml安装
步骤1:打开cmd,键入pip install wheel,先安装wheel库了才能安装.whl文件。
步骤2:
方法①直接pip install lxml,该方法有可能不成功;
方法②打开网址https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml
根据Python版本下载对应的whl包,如64位Python3.7,如下图,对应下载lxml-4.4.1-cp37-cp37m-win_amd64.whl,这是去年安装的,现在版本都有所变动。
在存放whl的文件夹中打开cmd,并执行以下代码,
pip install lxml-4.4.1-cp37-cp37m-win_amd64.whl
使用这种方法还有一些人不能安装。
方法③上述方法如果不行,把.whl修改成zip,并解压,把里面的两个文件夹复制到D:\Python\Lib\site-packages目录下,就可以了。
步骤3:验证安装是否成功
打开python,输入import lxml,如不报错,则成功。
(3)XPath语法讲解
要提取图一中“信息1”,用XPath只需1行代码:
info=selector.xpath(‘//div[@class=”useful”]/ul/li/text()’)
代码返回一个列表,
获取文本://标签1[@属性1=”属性值1”] /标签2[@属性2=”属性值2”]/……/text()
获取属性值://标签1[@属性1=”属性值1”] /标签2[@属性2=”属性值2”]/ @属性n
例1:标签1的选择
标签1的选择时要完整,要独特,如
<div class=”useful”>
<ul>
<li class=”info”>信息1</li>
<li class=”info”>信息2</li>
<li class=”info”>信息3</li>
</ul>
</div>
标签1可以选择
注意:
- 标签本身没有属性,可以省略。如果标签中有相同属性,也可以省略如
- 。所以要提取信息1、信息2和信息3时,代码如下
info=selector.xpath(‘//div[@class=”useful”]/text()’)
例2:以相同字符串开头:使用starts-with提取
<body>
<div id=”test-1”>内容1</div>
<div id=”test-2”>内容2</div>
<div id=”test-3”>内容3</div>
<div id=”useless”>内容4</div>
</body>
要提取内容1、内容2和内容3;如果不指定标签的属性,则会把内容4也提取出来。解决办法可以加字符串,如
//div[starts-with(@id,”test”)]/text()
例3:属性值包含相同字符串:使用contains提取
如果没有共同开头的字符段,但包含某相同的字符段,如
<body>
<div id=”123-test”>内容1</div>
<div id=”abd-text”>内容2</div>
<div id=”xyz-test”>内容3</div>
<div id=”useless”>内容4</div>
</body>
则starts-with改成contains,
content = selector.xpath(‘//div[contains(@id,”-test”)]/text()’)
for each in content;
print(each)
例4:对XPath提取的对象执行XPath
useful =selector.xpath(‘//div[@class=”useful”]’) #返回一个列表
info=useful[0].xpath(‘ul/li/text()’)
print(info)
例5:不同标签下的文字提取
<body>
<div id=test1”>
北京,
<span id=”test2”>
天安门广场
<ul>北侧是故宫
<li>西侧是人民大会堂</li>
</ul>
东侧是中国博物馆
</span>
中间是人民英雄纪念碑
</div>
</body>
如果使用
my =selector.xpath(‘//div[@id=”test1”]/text()’)
提取来的是“北京”和“中间是人民英雄纪念碑”,xpath没有把子标签自动提取出来。解决办法可以使用string(.)提取关键字。即对XPath提取的对象执行XPath。
data = selector.xpath(‘//div[@id=”test1”]’)[0]
my = data.xpath(‘string(.)’)
如要爬取百度财经新闻关于瑞幸咖啡的一段新闻,使用Google Chrome浏览器,具体操纵在空白点击右键,弹出对话框选择“检查”命令,出现开发者工具界面。如果我们想获得下图左侧标亮的第一段新闻,在下图右侧标亮处点击右键,按照下图所示选择即可,复制后得到路径,
//*[@id="article"]/div/p[1]/span/text()
这里的p[1]表明@id="article"下第1个
标签,数字是从1开始的,仔细观察p[1]代表新闻正文的第1段。
3.实例:爬取起点中文网的全部作品信息
(1)数据存储到excel
使用Python的第三方库xlwt,可将数据写入到Excel中,通过pip进行安装即可:
pip3 install xlwt
(2)爬虫思路
爬取的内容为起点中文网的男性作者作品信息(https://www.qidian.com/all/)
手动翻页,发现规律
https://www.qidian.com/all?orderId=&style=1&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=2
https://www.qidian.com/all?orderId=&style=1&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=3
https://www.qidian.com/all?orderId=&style=1&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=4
http://www.qidian.com/ all?page=,页码变换其他都不变。
需要爬取的信息有:小说名、作者ID、小说类型、完成情况、摘要和字数等
运用xlwt库,把爬取的信息存储在本地的Excel表格中。
比如提取小说名,如下图所示
复制的路径如下
/html/body/div[1]/div[5]/div[2]/div[2]/div/ul/li[1]/div[2]/h4/a
程序如下:
import xlwt
import requests
from lxml import etree
import time
all_info_list = []
def get_info(url):
html = requests.get(url)
selector = etree.HTML(html.text)
infos = selector.xpath('//ul[@class="all-img-list cf"]/li')
for info in infos:
title = info.xpath('div[2]/h4/a/text()')[0]
author = info.xpath('div[2]/p[1]/a[1]/text()')[0]
style_1 = info.xpath('div[2]/p[1]/a[2]/text()')[0]
style_2 = info.xpath('div[2]/p[1]/a[3]/text()')[0]
style = style_1+'·'+style_2
complete = info.xpath('div[2]/p[1]/span/text()')[0]
introduce = info.xpath('div[2]/p[2]/text()')[0].strip()
word = info.xpath('div[2]/p[3]/span/text()')[0].strip('万字')
info_list = [title,author,style,complete,introduce,word]
all_info_list.append(info_list)
time.sleep(1)
if __name__ == '__main__':
urls = ['http://www.qidian.com/all?page={}'.format(str(i)) for i in range(1,101)]
for url in urls:
get_info(url)
header = ['title','author','style','complete','introduce','word']
book = xlwt.Workbook(encoding='utf-8')
sheet = book.add_sheet('Sheet1')
for h in range(len(header)):
sheet.write(0, h, header[h])
i = 1
for list in all_info_list:
j = 0
for data in list:
sheet.write(i, j, data)
j += 1
i += 1
book.save('qidianxiaoshuo.xls')