爬蟲---xpath+jsonpath

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&currentPageNum=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&currentPageNum={}&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()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 上網(wǎng)原理 1、爬蟲概念 爬蟲是什麼? 蜘蛛,蛆,代碼中,就是寫了一段代碼,代碼的功能從互聯(lián)網(wǎng)中提取數(shù)據(jù) 互聯(lián)網(wǎng): ...
    riverstation閱讀 8,654評論 1 2
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,605評論 19 139
  • 20170531 這幾天重新拾起了爬蟲,算起來有將近5個月不碰python爬蟲了。 對照著網(wǎng)上的程序和自己以前寫的...
    八神蒼月閱讀 14,380評論 3 44
  • ···lxml用法源自 lxml python 官方文檔,更多內(nèi)容請直接參閱官方文檔,本文對其進行翻譯與整理。lx...
    小豐豐_72a2閱讀 1,101評論 0 1
  • XPath簡介 以下摘自維基百科 XPath (XML Path Language) is a query lan...
    geekpy閱讀 1,955評論 0 7

友情鏈接更多精彩內(nèi)容