1 xpath
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。
(1)基本介绍
/ 从根节点选取,
// 从所有匹配的节点选取
. 当前节点,
.. 当前的父节点
nodename 选取节点,
@ 选取节点的属性
通赔符 *, 选取若干路径用 | 分割
text() 选取该节点的文本内容
//img/@src: 选取所有img 节点的src属性
//img/../text 选取img节点的父节点下的text节点
//*/@src 选取任何节点的src 属性
(2)找到属性
result = html.xpath('//a/@href')
print(result)
(3)找文本
# 如果找某一标签的文本,而这个变迁下面还有其他的标签
# 那么只找这个标签的文本,子标签的文本不找。
result = html.xpath('//div/text()')
print(result)
# //text() 找到本标签以及所有子标签的文本
result = html.xpath('//div//text()')
for name in result:
print(name)
string 也是一种函数方法,可以提取子标签的文本
content = code.xpath('//div[@class="p_content "]/cc/div')
for i in content:
print(i.xpath('string(.)'))
(4)根据指定的标签寻找
result = html.xpath('//ul/li/a[@id="jd"]/text()')
print(result[0])
快速获得xpath的方法(需要修改一些细节)
二 BeautifulSoup
eautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据
(1) 获取属性值
bs = BeautifulSoup('index.html', 'lxml')
print(bs.a['href'])
(2) 获得文本
# string 获取的文本指的是本标签的文本
# 不包含子标签的文本
print(bs.div.string)
这种办法可以获得子标签的文本
content = soup.select('div.p_content cc div')
for i in content:
print(i.get_text())
(3) find 与 find_all
Html中的class 和id 不一样,id 必须是唯一的, 一个标签只能有一个ID
class 不是唯一的,不同的标签可以拥有同一个class,同一个标签也可以拥有多个class
# id 是唯一的,通过id 只能找一个,所以用find
print(bs.find(id="jd"))
# class 不是唯一的,通过class 来找 可能找到多个
# 注意class_ 这里有一个下划线
print(bs.find_all(class_="shopping"))
# find_all 是列表 ,find 是字符串
(4) select 的用法
# select--选择指定的标签
print(bs.select('title'))
# 当选择的对象有多个的时候,就获取多个的对象
print(bs.select('a'))
# . 表示类名 # 表示id
print(bs.select('.first'))
print(bs.select('#jd'))
表示根据层级关系寻找
soup.select('li.d_name a')
例子1:
通过提取百度贴吧的(发帖人)与(发帖内容) 来比较re,xpath,BeautifulSoup 的用法 这里只是对比提取不同,所以只对一页的内容进行比较
import re
from bs4 import BeautifulSoup
from lxml import etree
import requests
class SpiderCompare(object):
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
' (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
def get_code(self):
response = requests.get('https://tieba.baidu.com/p/5743456239?pn=1', headers=self.headers).text
return response
def use_re(self, code):
pattern = re.compile(r'<li class="d_name".*?<a.*?>(.*?)</a>'
r'.*?<cc.*?class="d_post_content j_d_post_content ">(.*?)</div>', re.S)
result = re.findall(pattern, code)
pattern = re.compile(r'<.*?>|<br>|</a>', re.S)
for name, content in result:
new_name = re.sub(pattern, '', name)
new_name = pattern.sub('', name)
# 两种写法
new_content = re.sub(pattern, '', content)
print(new_content)
def use_xpath(self, code):
new_code = etree.HTML(code)
name = new_code.xpath('//li[@class="d_name"]/a/text()')
for new in name:
print(new.replace(' ', '').strip('\n'))
content = new_code.xpath('//cc/div[@class="d_post_content j_d_post_content "]//text()')
for new in content:
print(new)
def use_soup(self, code):
soup = BeautifulSoup(code, 'lxml')
name = soup.select('li.d_name a')
for new in name:
print(new.get_text())
content = soup.select('cc div')
for new in content:
print(new.get_text())
def manager_spider(self):
code = self.get_code()
self.use_re(code)
self.use_xpath(code)
self.use_soup(code)
spider = SpiderCompare()
spider.manager_spider()
通过以上同时使用三种方法,打印content的内容,发现使用re和soup 会把一个标签里的文本输出在一行, 而 xpath 会以文本在浏览器中的显示方式 进行输出。
例子2:
通过提取天堂图片网,图片的src 和title属性,来比较soup和xpath的具体用法
from bs4 import BeautifulSoup
from lxml import etree
import requests
# 这是网页源码提取的部分
'''
<li>
<div class="il_img"><a href="/tupian/makelong_v47314/" title="美味的马卡龙图片" target="_blank">
<img src="http://img.ivsky.com/img/tupian/li/201803/13/macaroon-001.jpg" alt="美味的马卡龙图片"></a></div>
<p><a href="/tupian/makelong_v47314/" target="_blank">美味的马卡龙图片(12张)</a></p>
</li>
'''
class TianTangSpider(object):
def get_code(self):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
' (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
response = requests.get('http://www.ivsky.com/tupian/meishishijie/', headers=headers).text
return response
def use_xpath(self, code):
code = etree.HTML(code)
# 因为a标签下面嵌套着img标签,这里只获取a标签的href 属性
href = code.xpath('//div[@class="il_img"]/a')
for i in href:
print(i.get('href'))
image_list = code.xpath('//div[@class="il_img"]/a/img')
for name in image_list:
src = name.get('src')
alt = name.get('alt')
def use_soup(self, code):
soup = BeautifulSoup(code, 'lxml')
image_list = soup.select('div.il_img img')
for name in image_list:
src = name.get('src')
alt = name.get('alt')
def func_manager(self):
code = self.get_code()
self.use_xpath(code)
self.use_soup(code)
tian = TianTangSpider()
tian.func_manager()
总结:两种使用方法基本上没有区别,只有在调用各自方法的时候,书写有一些区别
xpath:
code = etree.HTML(code)
src_list = code.xpath('//div[@class=]/a/div')
# 注意//必须写,表示在根目录开始找,也可以在某个嵌套循环里不写,
soup
soup = BeautifulSoup(code, 'lxml')
src_list = soup.select('div.类名 img ')
# 标签与属性是通过.连接的 到下一级标签使用 空格 连接的。