クローラー 09 - xpath 分析

1. XPathを理解する

xpath は、XML ドキュメント内のコンテンツを検索するための言語です。
htmlは、xml のサブセットです。

<book>
    <id>1</id>
    <name>野花满地香</name>
    <price>1.23</price>
    <author>
        <nick>周大强</nick>
        <nick>周诺宁</nick>
    </author>
</book>

XML では、これらのタグはノードと呼ばれます。上記の場合、<book> は <id>、<name>、<price>、<author> の親ノードであり、それ以外の場合は <id>、<name>、<price> です。 >、<author> は <book> の子ノードです。

<id>、<name>、<price>、<author> は兄弟ノードです。

全体として、外側の層にある人をラップする人が親ノードになります。

#当要查找price的值,应该先从文档的根目录开始寻找
/book/price

2. xpath の概要

2.1 lxml モジュールのインストール

lxml モジュールのいくつかの関数を使用すると、xpath を使用して解析できます。

pip install lxml

 2.2 いくつかの簡単なケース (文法規則)

# xpath 是在XML文档中搜索内容的一门语言
# html 是xml的一个子集
from lxml import etree
xml = """      #首先导入一个xml数据
    <book>
        <id>1</id>
        <name>野花满地香</name>
        <price>1.23</price>
        <author>
            <nick id="10086">周大强</nick>
            <nick id="10010">周诺宁</nick>
            <nick class="joy">周杰伦</nick>
            <nick class="jolin">蔡依林</nick>
            <div>
                <nick>热热热热热热</nick>
            </div>
            <span>
                <nick>热热热热热热1</nick>
                <div>
                    <nick>热热热热热热3</nick>
                </div>
            </span>
        </author>
        <partner>
            <nick id="ppc">胖胖陈</nick>
            <nick id="ppbc">胖胖不陈</nick>
        </partner>
    </book>
"""
tree = etree.XML(xml)
#1. 想要拿到name的值
result1 = tree.xpath("/book/name/text()") # text()是用来获取文本值
print(result1) # >>> ['野花满地香']

#2. 获取author里nick的值
result2 = tree.xpath("/book/author/nick/text()")
print(result2)  # >>> ['周大强', '周诺宁', '周杰伦', '蔡依林']
#因为div下的nick与上面的nick不是在同一阶级上,所以找不到

#3. 获取author中div里的nick值
result3 = tree.xpath("/book/author/div/nick/text()")
print(result3)  # >>> ['热热热热热热']

#4. 获取author中所有的nick值
result4 = tree.xpath("/book/author//nick/text()") # // 获取父节点下所有的后代
print(result4)  # >>> ['周大强', '周诺宁', '周杰伦', '蔡依林', '热热热热热热', '热热热热热热1', '热热热热热热3']

#5. 获取热,热1
result5 = tree.xpath("/book/author/*/nick/text()") # * 表示获取该阶级下所有的nick值 相当于斗地主中的赖子
print(result5)  # >>> ['热热热热热热', '热热热热热热1']

#6. 获取book下所有的nick值
result6 = tree.xpath("/book//nick/text()")
print(result6)  # >>> ['周大强', '周诺宁', '周杰伦', '蔡依林', '热热热热热热', '热热热热热热1', '热热热热热热3', '胖胖陈', '胖胖不陈']

2.3 いくつかの詳細なケース (文法規則)

2.3.1 まずは事例演習用のhtmlファイルを作成します

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        <li><a href="http://www.baidu.com">百度</a></li>
        <li><a href="http://www.google.com">谷歌</a></li>
        <li><a href="http://www.sogou.com">搜狗</a></li>
    </ul>
    <ol>
        <li><a href="feiji">飞机</a></li>
        <li><a href="dapao">大炮</a></li>
        <li><a href="huojian">火箭</a></li>
    </ol>
    <div class="job">李嘉诚</div>
    <div class="common">胡辣汤</div>
</body>
</html>

2.3.2 事例演習コード + 分析 

from lxml import etree
#新版本的lxml中没有集成etree,所以需要在b.html后增加一个解析
tree = etree.parse("b.html",etree.HTMLParser()) #parse用于导入文件

#1. 获取百度,谷歌,搜狗
result1 = tree.xpath('/html/body/ul/li/a/text()')
print(result1) #   >>> ['百度', '谷歌', '搜狗']

#2. 根据索引来寻找想要的值->获取百度,谷歌,搜狗中其中的某一个
# xpath中索引是从1开始的
result2 = tree.xpath('/html/body/ul/li[1]/a/text()') # [数字] 表示索引
result3 = tree.xpath('/html/body/ul/li[2]/a/text()')
result4 = tree.xpath('/html/body/ul/li[3]/a/text()')
print(result2) #   >>> ['百度']
print(result3) #   >>> ['谷歌']
print(result4) #   >>> ['搜狗']

#3. 根据属性对应的属性值来寻找元素->寻找href的值是大炮的元素
result5 = tree.xpath('/html/body/ol/li/a[@href="dapao"]/text()') # [@xxx=xxx] 表示属性的筛选
result6 = tree.xpath('/html/body/ol/li/a[@href="huojian"]/text()')
print(result5) #   >>> ['大炮']
print(result6) #   >>> ['火箭']

#4. 遍历元素
request7 = tree.xpath('/html/body/ol/li')
for li in request7:
    # print(li) # 此时的request7里应该是存放着三个li节点
    #1. 接着从每一个li中提取到文字信息
    # 但是现在的li已经不是整体的根节点了,所以需要增加 ' ./ ' 表示定位到当前节点
    result8 = li.xpath('./a/text()') # 在li中继续去寻找,此时为相对查找
    print(result8)

    #2. 获取到值对应的属性,-> 拿到href值 @属性
    result9 = li.xpath('./a/@href') #拿到属性对应的值是加[],去掉[]就是获取属性了
    print(result9)
'''
    ['飞机']
    ['feiji']
    ['大炮']
    ['dapao']
    ['火箭']
    ['huojian']
'''
#5. 获取ul下所有的href属性
result10 = tree.xpath('/html/body/ul/li/a/@href')
print(result10)
#   >>> ['http://www.baidu.com', 'http://www.google.com', 'http://www.sogou.com']

2.3.3 いくつかのヒント 

まず、作成した HTML をブラウザで開き、右クリックして確認します。ページにコンテンツが多くて乱雑に見える場合は、必要なコンテンツをクリックすると、対応する位置がチェックバーが優れています。

 

 次に右クリックすると、コピー列に xpath をコピーするオプションが表示されます。この時点で xpath をコピーします。

/html/body/div[1]

次に、コピーした xpath をコードにインポートして、必要なデータを取得します。 

#6. 通过网页复制的xpath进行获取数据
result10 = tree.xpath('/html/body/div[1]/text()')
print(result10) #   >>> ['李嘉诚']

 3.XPath実戦、Zhubajie.com情報の取得

ウェブサイトアドレス[寧波美術価格_寧波美術見積もり]_寧波美術サービスアウトソーシング情報-Ningbo Zhubajie.com

各店舗の名前、価格、紹介、住所をクロールします。

 3.1 まず情報がソースコード内に存在するかどうかを確認します。関連する単語を検索することで情報を見つけることができます。情報はソースコード内に存在します。 

3.2 上記のケーススタディを通じて、コンテンツをレイヤーごとに取得するだけで十分です

ソース コードを分析すると、すべてのサービス プロバイダーが枠で囲まれていることがわかります。以下の対応する各 div が、探している各サービス プロバイダーの情報です。、上記のヒントを使用して xpath を取得したり、ルート ノードからレイヤーごとに検索したりできます。

 xpath を取得することで、少し変更する必要があります。[1] は全文の最初のサービスプロバイダーを表しており、取得する必要があるのはサービスプロバイダーの情報であるため、最後の div[1] を div に変更する必要があります。したがって、全体を表す div を直接見つける必要があります。

 

注意深く観察することで、各サービスプロバイダーのあらゆる情報を入手できます。ここでは 1 つのサービス プロバイダーのみが出力され、すべてのサービス プロバイダー情報は breal をコメントアウトするだけで済みます。

import requests
from lxml import etree
url = 'https://ningbo.zbj.com/search/f/?kw=%E7%BE%8E%E5%B7%A5'
response = requests.get(url=url)
#print(response.text)

#解析
html = etree.HTML(response.text)
# 定位
# 获取到的xpath -> /html/body/div[6]/div/div/div[2]/div[5]/div[1]
divs = html.xpath('/html/body/div[6]/div/div/div[2]/div[5]/div[1]/div') # 获取到所有服务商

#遍历,div就表示页面上一个个的服务商
for div in divs:
    name = div.xpath('./div/div/a[1]/div[1]/p/text()') #服务商店名
    addr = div.xpath('./div/div/a[1]/div[1]/div/span/text()') #服务商地址
    money = div.xpath('./div/div/a[2]/div[2]/div[1]/span[1]/text()') #服务费
    tittle = div.xpath('./div/div/a[2]/div[2]/div[2]/p/text()') #标签
    print(name)
    print(addr)
    print(money)
    print(tittle)
    break #用于方便观察,所以只输出一次

演算結果

 

ただし、実行結果を観察すると、完全ではなく、修理が必要であることがわかります。

3.3 改善 

#遍历,div就表示页面上一个个的服务商
for div in divs:
    name = div.xpath('./div/div/a[1]/div[1]/p/text()')[1].strip('\n')  # 服务商店名
    addr = ''.join(div.xpath('./div/div/a[1]/div[1]/div/span/text()'))  # 服务商地址
    money = ''.join(div.xpath('./div/div/a[2]/div[2]/div[1]/span[1]/text()')).strip('¥')  # 服务费
    tittle = ''.join(div.xpath('./div/div/a[2]/div[2]/div[2]/p/text()'))  # 标签
    print(name)
    print(addr)
    print(money)
    print(tittle)
    break  # 用于方便观察,所以只输出一次

 

おすすめ

転載: blog.csdn.net/m0_48936146/article/details/124639539