自学Python爬虫笔记(day6)

发布时间 2023-04-14 15:59:06作者: Peom`

环境python3.9版本及以上,开发工具pycharm

 

XPath解析:

XPath是一门在XML文档中查找信息的语言,XPath可以用来在XML文档中对元素和属性进行遍历,而我们熟知的HTML恰巧属于XML中的一个子集,所以完全可以用XPath去查找html中的内容。

首先看:

<book>
    <id>1</id>
    <name>野花遍地香</name>
    <price>1.23</price>
    <author>
        <nick id="10086">周大强</nick>
        <nick id="10010">周芷诺</nick>
     </author>
</book>

在上述html中,book、id、name、price……都被称为节点;id、name、price、author都被称为book的子节点;book被称为id、name、price、author的父节点;id、name、price、author被称为兄弟节点。

下面通过一些例子来理解:

from lxml import etree

# 如果pycharm报错,可以考虑这种导入方式
# from lxml import html
# etree = html,etree

xml = '''
<book>
    <id>1</id>
    <name>野花遍地香</name>
    <price>1.23</price>
    <nick>臭豆腐</nick>
    <author>
        <nick id="10086">周大强</nick>
        <nick id="10010">周芷诺</nick>
        <nick class="jay">周杰伦</nick>
        <nick class="jolin">蔡依林</nick>
        <div>
            <nick>惹了</nick>
        </div>
    </author>
    <partner>
        <nick id="ppc">胖胖陈</nick>
        <nick id="ppbc">胖胖不沉</nick>
    </partner>
</book>
'''
# 此时练习只使用XML
et = etree.XML(xml)
# result = et.xpath('/book')      # / 表示根节点
# result = et.xpath('/book/name')     # 在xpath中间的/表示的是儿子
# result = et.xpath('/book/name/text()')[0]       # text() 拿文本
# result = et.xpath('/book//nick')        # // 表示的是子孙后代
# result = et.xpath('/book/*/nick/text()')        # * 通配符
# result = et.xpath('/book/author/nick[@class="jay"]/text()')     # []表示属性筛选,@属性名=值 类似bs4中find(Nick,attrs={'class': 'jay'})
result = et.xpath('/book/partner/nick/@id')     # 最后一个/表示拿到Nick里面的id的内容,@属性。可以直接拿到属性值
print(result)


# xpath处理HTML
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="huoche">火车</a></li>
    </ol>
    <div class="job">李嘉诚</div>
    <div class="common">胡辣汤</div>
</body>
</html>
'''

et = etree.HTML(html)
# li_list = et.xpath('/html/body/ul/li[2]/a/text()')
# print(li_list)

ll = et.xpath('//li')
for i in ll:
    href = i.xpath('./a/@href')[0]      # ./表示当前节点
    text = i.xpath('./a/text()')[0]     # ./表示当前节点
    print(text, href)

下面是对基础知识掌握后,跟做的一个案例:

'''
1.拿到页面源代码
2.从页面源代码中提取你需要的数据,价格,名称, 公司名称
'''
import requests
from lxml import etree

url = "https://beijing.zbj.com/search/service/?l=0&kw=saas&r=2"
resp = requests.get(url)
resp.encoding = 'utf-8'
# print(resp.text)

# 提取数据
et = etree.HTML(resp.text)
divs = et.xpath('//div[@class="service-card-wrap"]')
for div in divs:
    # 此时的div就是一条数据,对应一个商品信息
    # 商品价格
    price = div.xpath("./div/div[3]/div[1]/span/text()")
    if not price:   # 过滤无用数据
        continue
    price = price[0]
    company = div.xpath("./div/a/div[2]/div[1]/div/text()")[0]
    name = div.xpath("./div/div[3]/div[2]/a/text()")[0]
    name = ''.join(name)
    print(name+"\t", company+"\t", price+"\t")

由于现在这个界面变成了JS动态界面,我们发送一次请求只能获取到10条数据,然而在我们查看页面源代码时,发现它的HTML框架存在,数据也存在,但是是一次请求时分成多个时延发送,所以我们请求一次值获取到了第一次出现的数据,那些后面缓冲出来的数据并没有一次性爬取到,当我们把过滤无用数据这段代码去掉,就可以发现剩下的40条数据都为空,所以此次数据爬虫应当算成功!

 

PyQuery解析:

直接看代码

from pyquery import PyQuery

# html = """
#     <ul>
#         <li class="aaa"><a href="http://www.google.com">谷歌</a></li>
#         <li class="aaa"><a href="http://www.baidu.com">百度</a></li>
#         <li class="bbb" id='qq'><a href="http://www.qq.com">腾讯</a></li>
#         <li class="bbb"><a href="http://www.yuanlai.com">源来</a></li>
#     </ul>
# """

# 加载html内容
# p = PyQuery(html)

# print(p)
# print(type(p))
# pyquery对象接(css选择器)

# a = p('a')
# print(a)
# print(type(a))      # 依然是pyquery对象

# 链式操作
# a = p("li")("a")
# print(a)

# a = p("li a")
# print(a)

# a = p(".aaa a")      # class="aaa"
# print(a)

# a = p("#qq a")      #id="qq"
# print(a)

# href = p("#qq a").attr("href")  # 拿属性
# text = p("#qq a").text()    # 拿文本
# print(text)

# 坑,如果多个标签同时拿属性,只能默认拿到第一个
# href = p("li a").attr("href")
# print(href)

# 多个标签拿属性
# it = p("li a").items()
# for item in it:     # 从迭代器中拿到每一个标签
#     href = item.attr("href")    # 拿到href属性
#     text = item.text()
#     print(text, href)

# 快速总结:
# 1.pyquery(选择器)
# 2.item()  当选择器选择的内容有很多时,需要一个一个处理时‘
# 3.attr(属性名):获取属性信息
# 4.text()  获取文本


# div = '''
#     <div><span>i love you</span></div>
# '''
# p = PyQuery(div)
# html = p("div").html()  # 全都要
# text = p("div").text()  # 只要文本,所有的html标签都被过滤掉
# print(html)
# print(text)


html = '''
<HTML>
    <div class='aaa'>哒哒哒</div>
    <dic class='bbb'>嘟嘟嘟</div>
</HTML>
'''

p = PyQuery(html)

# p("div.aaa").after('''<div class='ccc'>吼吼吼</div>''')    # 在xxxx标签后面添加xxxx新标签
# p("div.aaa").append('''<span>i love you</span>''')      # 在xxxx标签中添加添加xxxx新标签
#
# p("div.bbb").attr(("class", "aaa"))     # 修改属性
# p("div.bbb").attr("id", "123456")       #新增属性,前提是该标签,没有这个属性
# p("div.bbb").remove_attr("id")      # 删除属性
# p("div.bbb").remove()       # 删除标签
# print(p)
from pyquery import PyQuery

# html = """
#     <ul>
#         <li class="aaa"><a href="http://www.google.com">谷歌</a></li>
#         <li class="aaa"><a href="http://www.baidu.com">百度</a></li>
#         <li class="bbb" id='qq'><a href="http://www.qq.com">腾讯</a></li>
#         <li class="bbb"><a href="http://www.yuanlai.com">源来</a></li>
#     </ul>
# """

# 加载html内容
# p = PyQuery(html)

# print(p)
# print(type(p))
# pyquery对象接(css选择器)

# a = p('a')
# print(a)
# print(type(a))      # 依然是pyquery对象

# 链式操作
# a = p("li")("a")
# print(a)

# a = p("li a")
# print(a)

# a = p(".aaa a")      # class="aaa"
# print(a)

# a = p("#qq a")      #id="qq"
# print(a)

# href = p("#qq a").attr("href")  # 拿属性
# text = p("#qq a").text()    # 拿文本
# print(text)

# 坑,如果多个标签同时拿属性,只能默认拿到第一个
# href = p("li a").attr("href")
# print(href)

# 多个标签拿属性
# it = p("li a").items()
# for item in it:     # 从迭代器中拿到每一个标签
#     href = item.attr("href")    # 拿到href属性
#     text = item.text()
#     print(text, href)

# 快速总结:
# 1.pyquery(选择器)
# 2.item()  当选择器选择的内容有很多时,需要一个一个处理时‘
# 3.attr(属性名):获取属性信息
# 4.text()  获取文本


# div = '''
#     <div><span>i love you</span></div>
# '''
# p = PyQuery(div)
# html = p("div").html()  # 全都要
# text = p("div").text()  # 只要文本,所有的html标签都被过滤掉
# print(html)
# print(text)


html = '''
<HTML>
    <div class='aaa'>哒哒哒</div>
    <dic class='bbb'>嘟嘟嘟</div>
</HTML>
'''

p = PyQuery(html)

# p("div.aaa").after('''<div class='ccc'>吼吼吼</div>''')    # 在xxxx标签后面添加xxxx新标签
# p("div.aaa").append('''<span>i love you</span>''')      # 在xxxx标签中添加添加xxxx新标签
#
# p("div.bbb").attr(("class", "aaa"))     # 修改属性
# p("div.bbb").attr("id", "123456")       #新增属性,前提是该标签,没有这个属性
# p("div.bbb").remove_attr("id")      # 删除属性
# p("div.bbb").remove()       # 删除标签
# print(p)

下面是跟做未成功的案例(它网站变化了,我试过自己的方式,没成功,所以就把老师的抄下来以便自己学习)

'''
1.提取页面源代码
2.解析页面源代码,提取数据
'''
import requests
from pyquery import PyQuery


def get_page_source(url):
    resp = requests.get(url)
    # resp.encoding = 'gbk'
    return resp.text

def parse_page_source(html):
    doc = PyQuery(html)
    mt_list = doc(".my-10").items()      # class="mt-10"
    for mt in mt_list:      # 拿到每一个mt

        # 判断是否有汽车经销商
        if not  mt("div > dl:nth-child(3) > dt:contains(购车经销商)"):
            mt("div > dl:nth-child(2)").after(PyQuery('''
                <dl class="choose-dl">
                    <dt>购车经销商</dt>
                    <dd>
                        <a href="###" class="js-dearname" data-val="125965,47759"
                            &nbsp
                        </a>
                    </dd>
                </dl>
            '''))       # 向 地点 后添加购车经销商进去

        # 提取购买的车型
        # 想要在已经提取的内容中获取第一个怎么办?  eq(0)
        # nth—child(1) 在css进行选择的时候,选取第一个位置的内容
        chexing = mt("div > dl:nth-child(1) > dd").eq(0).text().replace("\n", "").replace(" ", "")
        didian = mt("div > dl:nth-child(2) > dd").text()
        shijian = mt("div > dl:nth-child(4) > dd").text()
        jiage = mt("div > dl:nth-child(5) > dd").text().replace(" 万元", "")
        youhao = mt("div > dl:nth-child(6) > dd > p:nth-child(1)").text().replace(" 升/百公里", "")
        gonglishu = mt("div > dl:nth-child(6) > dd > p:nth-child(2)").text().replace(" 公里", "")
        other = mt("div > div > dl > dd").text().split()
        # 存储到文件中
        with open("A8.csv", mode="w", encoding='utf-8') as f:
            f.write(chexing,didian, shijian, jiage, youhao, gonglishu, other)
        f.close()


def main():
    url = 'https://k.autohome.com.cn/146/'
    # 1.提取页面源代码
    html = get_page_source(url)
    # 2.解析页面源代码,提取数据
    parse_page_source(html)


if __name__ == "__main__":
    main()