xpath語法
xml : 和json是一樣的,用在數(shù)據(jù)交互和傳輸中,但是到現(xiàn)在用的基本上都是json格式
為什么使用json格式?因為js原生支持
xpath : 就是用來解析xml數(shù)據(jù)的
因為這個xml和html很像,所以在python里面有一個第三方庫 lxml,提供了一些xpath可以解析html的一些函數(shù),你可以直接使用
安裝lxml
pip install lxml
xpath簡單語法:
/ ----------根節(jié)點開始查找
// --------從任意位置開始查找
. ---------從當(dāng)前節(jié)點開始查找
.. -----從上一級節(jié)點開始查找
@ -----------選取屬性
bookstore/book :查找bookstore這個節(jié)點下面所有的book,直接子節(jié)點
//book : 在整個文檔中查找所有的book
bookstore//book :查找bookstore下面所有的book
//@lang :-查找所有擁有l(wèi)ang屬性的節(jié)點
bookstore/book[1] :查找第一個book,下標從1開始
bookstore/book[last()] :-最后一個book
bookstore/book[last()-1] : 倒數(shù)第二個
//title[@lang] :所有的有l(wèi)ang屬性的title
//title[@lang='eng'] :所有的lang屬性的值為eng的title節(jié)點
xpath使用
安裝xpath插件
- 啟動和關(guān)閉插件: ctrl + shift + x
常用的xpath
(1)屬性定位
- 查找id=kw的input框
//input[@id="kw"]
(2)層級和索引定位
//div[@id="head"]/div/div[3]/a[2]
(3)模糊匹配
contains
class屬性包含av的所有a
//a[contains(@class,"av")]
內(nèi)容包含產(chǎn)品的所有a
//a[contains(text(),"產(chǎn)品")]
starts_with
starts-with
class以m開頭的所有a
//a[starts-with(@class,"m")]
內(nèi)容以新開頭的所有a
//a[starts-with(text(),"新")]
(4)取文本和屬性
- 找內(nèi)容以新開頭的所有a標簽的文本內(nèi)容
//a[starts-with(text(),"新")]/text()
- 找內(nèi)容以新開頭的所有a標簽的href屬性
//a[starts-with(text(),"新")]/@href
代碼中操作xpath
步驟:給一個網(wǎng)頁字符串,會將網(wǎng)頁字符串生成對象,然后根據(jù)對象的xpath方法去找指定的節(jié)點即可
from lxml import etree
# 將本地的文件生成tree對象
tree = etree.parse('xpath.html')
# ret = tree.xpath('//li[@id="fei"]')
# ret = tree.xpath('//div[@class="mingju"]/ul/li[2]/a')
# ret = tree.xpath('//li[contains(text(),"花")]')
# ret = tree.xpath('//a[starts-with(@class,"y")]/text()')
# ret = tree.xpath('//a[starts-with(@class,"y")]/@href')
ret = tree.xpath('//div[@id="xing"]//text()')
string = '-'.join(ret).replace('\n', '').replace('\t', '')
print(string)
本地測試
【注】獲取標簽里面還有標簽的內(nèi)容的時候
obj/text() 只能找到本標簽里面的內(nèi)容,返回的都是列表,列表需要自己處理
obj//text() 標簽里面所有的內(nèi)容,返回的是列表,列表需要處理
下載圖片例子
sc.chinaz.com
http://sc.chinaz.com/tag_tupian/YaZhouMeiNv.html 第一頁
http://sc.chinaz.com/tag_tupian/yazhoumeinv_2.html 第二頁
from lxml import etree
import time
import urllib.request
import urllib.parse
import os
def handle_request(url, url_er, page):
if page == 1:
url = url
else:
url = url_er.format(page)
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',
}
return urllib.request.Request(url=url, headers=headers)
def parse_content(content):
# 生成tree對象
tree = etree.HTML(content)
# 寫xpath,來獲取所有的圖片的image_src
image_src_list = tree.xpath('//div[@id="container"]//img/@src2')
image_alt_list = tree.xpath('//div[@id="container"]//img/@alt')
# print(image_src_list)
# print(len(image_src_list))
for image_src in image_src_list:
dirname = 'meinv'
if not os.path.exists(dirname):
os.mkdir(dirname)
filename = image_alt_list[image_src_list.index(image_src)]
suffix = image_src.split('.')[-1]
filename = filename + '.' + suffix
filepath = os.path.join(dirname, filename)
print('正在下載%s。。。。。。' % filename)
urllib.request.urlretrieve(image_src, filepath)
print('結(jié)束下載%s' % filename)
time.sleep(2)
def main():
start_page = int(input('請輸入起始頁碼:'))
end_page = int(input('請輸入結(jié)束頁碼:'))
url = 'http://sc.chinaz.com/tag_tupian/YaZhouMeiNv.html'
url_er = 'http://sc.chinaz.com/tag_tupian/yazhoumeinv_{}.html'
for page in range(start_page, end_page + 1):
print('正在下載第%s頁。。。。。。' % page)
request = handle_request(url, url_er, page)
content = urllib.request.urlopen(request).read().decode('utf8')
# 解析內(nèi)容函數(shù)
parse_content(content)
print('結(jié)束下載第%s頁' % page)
time.sleep(2)
if __name__ == '__main__':
main()
懶加載技術(shù)
只顯示可視區(qū)內(nèi)的圖片,不再可視區(qū)內(nèi)的不顯示,等用戶滾動滾動條,圖片呈現(xiàn)在可視區(qū)的時候在顯示
如何實現(xiàn)的?
<img src='xxx'>
<img src2='xxx'> => 出現(xiàn)在可視區(qū),js動態(tài)修改為 <img src='xxx'>
data-original=xxx
class='lazy'
data-src='xxx'
json處理
- 獲取豆瓣電影的json數(shù)據(jù)寫入txt
import json
import urllib.request
import urllib.parse
url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=20&limit=20'
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',
}
request = urllib.request.Request(url=url, headers=headers)
content = urllib.request.urlopen(request).read().decode('utf8')
# print(content)
# 將json格式數(shù)據(jù)轉(zhuǎn)化為python對象
obj = json.loads(content)
# print(type(obj))
# 現(xiàn)在的obj是一個列表,列表里面都是字典
lt = []
# 遍歷列表,依次提取每一個字典里面的電影的名字和評分
for movie in obj:
title = movie['title']
score = movie['score']
# movie['xixi']['hehe']['haha'][0]['lala']
image_url = movie['cover_url']
item = {
'電影名字': title,
'電影評分': score,
'電影海報': image_url
}
lt.append(item)
string = json.dumps(lt, ensure_ascii=False)
with open('movie1.txt', 'w', encoding='utf8') as fp:
fp.write(string)
jsonpath
jsonpath是用來解析json數(shù)據(jù)的
格式: {} [] "" , :
python如何解析json格式
(1)自帶數(shù)據(jù)類型進行解析
import json
json.dumps() : 將python對象轉(zhuǎn)化為json格式字符串
ensure_ascii=False 寫入文件中文顯示
json.loads() : 將json格式字符串轉(zhuǎn)化為python對象
(2)jsonpath解析(了解)
pip install jsonpath
http://blog.csdn.net/luxideyao/article/details/77802389
/ $ 根元素
. @ 當(dāng)前元素
/ . 層級分隔符
// .. 任意位置查找
- jsonpath使用規(guī)則
import json
import jsonpath
fp = open('book.json', 'r', encoding='utf8')
string = fp.read()
fp.close()
# 將json格式字符串轉(zhuǎn)化為python對象
obj = json.loads(string)
# 使用jsonpath
# 查找所有book的author節(jié)點內(nèi)容
# ret = jsonpath.jsonpath(obj, '$.store.book[*].author')
# 從根下面開始找所有的author
ret = jsonpath.jsonpath(obj, '$..author')
# 查找store下面的所有節(jié)點
ret = jsonpath.jsonpath(obj, '$.store.*')
# 查找store下面的所有price節(jié)點
ret = jsonpath.jsonpath(obj, '$.store..price')
# 查找第三本book
ret = jsonpath.jsonpath(obj, '$..book[2]')
# 查找最后一本書籍
ret = jsonpath.jsonpath(obj, '$..book[(@.length-1)]')
print(ret)
淘寶評論---實戰(zhàn)
用戶頭像,用戶昵稱,評論內(nèi)容,評論圖片,評論時間,手機信息
https://rate.taobao.com/feedRateList.htm?auctionNumId=559141739630&userNumId=100340983¤tPageNum=3&pageSize=20
import json
import jsonpath
import urllib.request
import urllib.parse
import time
# 用來存放所有的評論信息
items = []
def handle_request(page, url):
url = url.format(page)
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',
}
return urllib.request.Request(url=url, headers=headers)
def parse_content(content):
# 如何解析content
# 處理content,將其轉(zhuǎn)化為合法的json格式字符串
content = content.strip('() \n\t\r')
# print(content)
obj = json.loads(content)
# print(type(obj))
# 提取出來所有的評論
comments_list = obj['comments']
# 遍歷列表,依次提取每一條評論的你要的信息
for comment in comments_list:
# 用戶頭像
# avatar = comment['user']['avatar']
avatar = jsonpath.jsonpath(comment, '$..avatar')[0]
# 用戶昵稱
nick = comment['user']['nick']
# 評論內(nèi)容
neirong = comment['content']
# 圖片
photos_list = comment['photos']
photos = []
for photo in photos_list:
# 獲取小圖
little_image = photo['thumbnail']
# 獲取大圖
big_image = photo['url']
photos.append((little_image, big_image))
# 時間
ping_time = comment['date']
# 手機信息
info = jsonpath.jsonpath(comment, '$..sku')[0]
item = {
'用戶頭像': avatar,
'用戶昵稱': nick,
'評論內(nèi)容': neirong,
'曬圖': photos,
'評論時間': ping_time,
'手機信息': info,
}
items.append(item)
def main():
url = 'https://rate.taobao.com/feedRateList.htm?auctionNumId=559141739630&userNumId=100340983¤tPageNum={}&pageSize=20'
start_page = int(input('請輸入起始頁碼:'))
end_page = int(input('請輸入結(jié)束頁碼:'))
for page in range(start_page, end_page + 1):
# for page in range(1, 2):
print('正在爬取第%s頁......' % page)
request = handle_request(page, url)
content = urllib.request.urlopen(request).read().decode('utf8')
parse_content(content)
print('結(jié)束爬取第%s頁......' % page)
time.sleep(2)
# 爬取完畢, 寫入到文件中
string = json.dumps(items, ensure_ascii=False)
with open('taobao.json', 'w', encoding='utf8') as fp:
fp.write(string)
if __name__ == '__main__':
main()