一、基本概念
不同的网页结构,我们灵活的采用不同的技术。
• XPath(XML Path Language)是一种XML的查询语言,他能在XML树状结构中寻找节点。XPath 用于在 XML 文档中通过元素和属性进行导航
• xml是一种标记语法的文本格式,xpath可以方便的定位xml中的元素和其中的属性值。
html 超文本标记语言;xml 可扩展标记语言;lxml 是一个Python第三方的库 它可以把这个html文本转换成xml对象(element对象) 使用xpath语法进行导航了。
结点的关系:
xml_content = '''
<bookstore>
<book>
<title lang='eng'>Harry Potter</title>
<author>JK.Rowing</author>
<year>2005</year>
<price>29<price>
</book>
</bookstore>
'''
父(Parent) :book元素是title、author、year、price元素的父
子(Children) :title、author、year、price都是book元素的子
二、xpath基本用法
1、启用快捷键 ctrl + shift + x
2、基本语法
比如,我们要爬取下图中红框处的‘python开发工程师’,第一步是点击绿框中的小箭头,之后鼠标移到红框处,控制台就选定到黄框,也就是一个div标签中的classs属性值为iteminfo__line1__jobname的
由此,我们xpath可以写成:
//div[@class=“iteminfo__line1__jobname”]/span/@title
具体说明:
// 不要考虑位置
[] 谓语 用来查找某个特定的节点或者包含某个指定的值的节点 谓语被镶嵌在方括号当中
@ class=“iteminfo__line1__jobname” 选取某个属性
/ 去找这个 class=“iteminfo__line1__jobname” div标签下面的 span标签
@title 选取title属性
三、lxml模块的使用
1、安装 pip install lxml -i https://pypi.douban.com/simple
2 、功能 html 转换成element对象 有了element对象之后就可以使用xpath语法进行导航了
3 、使用
3.1 from lxml import etree
3.2 得到目标网页的源代码文件(html)
3.3 etree.HTML(网页源码) --> element对象
3.4 element.xpath(xxxx)
from lxml import etree
import csv
wb_data = """
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
"""
html_element = etree.HTML(wb_data)
# 获取li标签下面的href属性
links = html_element.xpath('//li/a/@href')
# print(links)
# 获取li标签下面a标签的文本内容
result = html_element.xpath('//li/a/text()')
# print(result)
# 需求是把二者的结果保存到一个字典当中然后存储的csv文件当中
# 例如 {'href':'link1.html','title':'first item'}, {'href':'link2.html','title':'second item'}...
titles = ('href','title')
lst = []
for link in links:
d = {}
d['href'] = link
# print(links.index(link))
d['title'] = result[links.index(link)]
# print(d)
lst.append(d)
with open('练习.csv','w',encoding='utf-8',newline='') as file_obj:
writer = csv.DictWriter(file_obj,titles)
writer.writeheader()
writer.writerows(lst)
结果:
四、豆瓣top250电影
需求: 爬取豆瓣top250电影详情页 (1-10页)的url、电影的名字、评分 、引言 ,并 保存到csv文件当中。
import requests
from lxml import etree
import csv
# 目标Url
doubanUrl = 'https://movie.douban.com/top250?start={}&filter='
# 定义一个函数 获取网页源码
def getSource(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36'
}
response = requests.get(url,headers=headers)
response.encoding = 'utf-8'
return response.text
# 解析数据 电影的名字 评分 引言 详情页的url
def getEveryItem(source):
html_element = etree.HTML(source)
# class="info" 电影的名字 评分 引言 详情页的url 25
movieItemList = html_element.xpath('//div[@class="info"]')
movieList = []
for eachMoive in movieItemList:
movieDict = {}
title = eachMoive.xpath('div[@class="hd"]/a/span[@class="title"]/text()') # 标题
otherTitle = eachMoive.xpath('div[@class="hd"]/a/span[@class="other"]/text()') # 副标题
link = eachMoive.xpath('div[@class="hd"]/a/@href')[0] # url
star = eachMoive.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()')[0] # 评分
quote = eachMoive.xpath('div[@class="bd"]/p[@class="quote"]/span/text()') # 引言(名句),有的电影没有引言
# 第一种异常处理
# 第二种非空判断
if quote:
quote = quote[0]
else:
quote = ''
movieDict['title'] = ''.join(title + otherTitle) # 主标题要 + 父标题
movieDict['url'] = link
movieDict['star'] = star
movieDict['quote'] = quote
print(movieDict)
movieList.append(movieDict)
return movieList
# 保存数据
def writeData(movieList):
with open('douban.csv','w',encoding='utf-8',newline='') as file_obj:
writer = csv.DictWriter(file_obj,fieldnames=['title','star','quote','url'])
writer.writeheader()
for each in movieList:
writer.writerow(each)
if __name__ == '__main__':
movieList = []
for i in range(10):
pageLink = doubanUrl.format(i * 25)
source = getSource(pageLink)
movieList = getEveryItem(source) # 保存的最后一页 movieList = movieList + getEveryItem(source) a = 1 a += 1
writeData(movieList)
补充:
join() 方法:以指定的方式把字符串或列表连接成一个新的字符串,并返回。
a = ['1','2','3']
b = '-'.join(a)
print(b) # 1-2-3
c = 'hello'
d = '*'.join(c)
print(d) # h*e*l*l*o
在爬虫笔记25中有具体应用案例。