爬虫---xpath+jsonpath

xpath语法

xml : 和json是一样的,用在数据交互和传输中,但是到现在用的基本上都是json格式
为什么使用json格式?因为js原生支持

xpath : 就是用来解析xml数据的
因为这个xml和html很像,所以在python里面有一个第三方库 lxml,提供了一些xpath可以解析html的一些函数,你可以直接使用

安装lxml

pip install lxml

xpath简单语法:

/ ----------根节点开始查找
// --------从任意位置开始查找
. ---------从当前节点开始查找
.. -----从上一级节点开始查找
@ -----------选取属性

bookstore/book :查找bookstore这个节点下面所有的book,直接子节点
//book : 在整个文档中查找所有的book
bookstore//book :查找bookstore下面所有的book
//@lang :-查找所有拥有lang属性的节点
bookstore/book[1] :查找第一个book,下标从1开始
bookstore/book[last()] :-最后一个book
bookstore/book[last()-1] : 倒数第二个
//title[@lang] :所有的有lang属性的title
//title[@lang='eng'] :所有的lang属性的值为eng的title节点

xpath使用

安装xpath插件

  • 启动和关闭插件: 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")]

内容包含产品的所有a
//a[contains(text(),"产品")]

starts_with
starts-with
class以m开头的所有a
//a[starts-with(@class,"m")]

内容以新开头的所有a
//a[starts-with(text(),"新")]

(4)取文本和属性

  • 找内容以新开头的所有a标签的文本内容

//a[starts-with(text(),"新")]/text()

  • 找内容以新开头的所有a标签的href属性

//a[starts-with(text(),"新")]/@href

代码中操作xpath

步骤:给一个网页字符串,会将网页字符串生成对象,然后根据对象的xpath方法去找指定的节点即可

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)

本地测试

【注】获取标签里面还有标签的内容的时候
obj/text() 只能找到本标签里面的内容,返回的都是列表,列表需要自己处理
obj//text() 标签里面所有的内容,返回的是列表,列表需要处理

下载图片例子

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('结束下载%s' % filename)
        time.sleep(2)

def main():
    start_page = int(input('请输入起始页码:'))
    end_page = int(input('请输入结束页码:'))
    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')
        # 解析内容函数
        parse_content(content)
        print('结束下载第%s页' % page)
        time.sleep(2)

if __name__ == '__main__':
    main()

懒加载技术

只显示可视区内的图片,不再可视区内的不显示,等用户滚动滚动条,图片呈现在可视区的时候在显示
如何实现的?


  => 出现在可视区,js动态修改为  
data-original=xxx
class='lazy'
data-src='xxx'

json处理

  • 获取豆瓣电影的json数据写入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格式数据转化为python对象
obj = json.loads(content)

# print(type(obj))
# 现在的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数据的

格式: {} [] "" , :
python如何解析json格式

(1)自带数据类型进行解析

import json
json.dumps() : 将python对象转化为json格式字符串
ensure_ascii=False  写入文件中文显示
json.loads() : 将json格式字符串转化为python对象

(2)jsonpath解析(了解)

pip install jsonpath

http://blog.csdn.net/luxideyao/article/details/77802389
/ $ 根元素
. @ 当前元素
/ . 层级分隔符
// .. 任意位置查找

  • jsonpath使用规则
import json
import jsonpath

fp = open('book.json', 'r', encoding='utf8')
string = fp.read()
fp.close()

# 将json格式字符串转化为python对象
obj = json.loads(string)

# 使用jsonpath
# 查找所有book的author节点内容
# ret = jsonpath.jsonpath(obj, '$.store.book[*].author')

# 从根下面开始找所有的author
ret = jsonpath.jsonpath(obj, '$..author')

# 查找store下面的所有节点
ret = jsonpath.jsonpath(obj, '$.store.*')

# 查找store下面的所有price节点
ret = jsonpath.jsonpath(obj, '$.store..price')

# 查找第三本book
ret = jsonpath.jsonpath(obj, '$..book[2]')

# 查找最后一本书籍
ret = jsonpath.jsonpath(obj, '$..book[(@.length-1)]')
print(ret)

淘宝评论---实战

用户头像,用户昵称,评论内容,评论图片,评论时间,手机信息
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,将其转化为合法的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']
        # 评论内容
        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,
            '评论内容': 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('请输入结束页码:'))
    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('结束爬取第%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()

你可能感兴趣的:(爬虫---xpath+jsonpath)