Python-爬虫(四)xpath和lxml模块入门使用爬取天堂电影

目录

xpath简介

 xpath语法

lxml

lxml和xpath结合提取html中的内容

爬取天堂电影案例


xpath简介

xpath(xml path language)是一门在xml和html文档中查找信息的语言,可用来在xml和html文档中对元素和属性进行遍历。

我们爬取页面之后用xpath语法获取我们需要的内容。

可以使用谷歌插件在页面中直接写xpath语法。可以从我的资源中下载。使用效果如下:

 xpath语法

语法比较简单可以参考: xpath语法

表达式描述
nodename选取此节点的所有子节点。
/从根节点选取。
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.选取当前节点。
..选取当前节点的父节点。
@选取属性。

选取节点

xpath使用路径表达式来选取xml文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。

lxml

lxml 是一种使用 Python 编写的库,可以迅速、灵活地处理 XML 和 HTML。lxml库结合libxml2快速强大的特性,使用xpath语法来进行文件格式解析,与Beautiful相比,效率更高。经过lxml处理过的html文本会得到一个Element对象,可以直接通过xpath语法进行过滤。

直接解析文本

但是直接tostring会得到一个字节类型的内容,如果需要我可以进行重写编码再转码。

从文件中读取html

在项目目录下新建一个test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>你好</h1>
</body>
</html>

lxml中有一个parse函数可以传入文件进行解析,但是我们直接使用有报错:

我们看到报错是xml的语法错误,我们知道xml都是一个开始节点对应一个结束节点的。但是我们Html中并不都是这样的。这时因为parse函数默认是采用xml解析器去解析的,上面的html函数是直接html解析器解析。因此使用parse的时候我们要指定html解析器。

lxml和xpath结合提取html中的内容

准备了拉勾网的职位网页。

提取内容:

用parse函数解析出来的filehtml是个Element对象,用它调用xpath函数,参数就是xpath语法表达式,可以得到选择的标签。但是注意这里得到的结果是个Element对象数组,而且这个数组我们根据索引获取的时候是从1开始的。

我们通过遍历可以得到内容:

根据需要在xpath函数中填写表达式就可以得到想要的结果。

再举一个例子,如果要获取a标签中的href属性值,则可以按照如下方式:

注意下面获取的是div下的直接子节点a标签,因为只用了一个"/",如果a标签不是直接子元素又想获取就要用"//"

如果想获取标签中的文本信息,如职位信息:

可以使用text()函数。要注意"/"  和"//"的区别。

还有一点"."需要注意,假如我们要根据下面

<div class="position">获取职位信息的href值。


我们可以根据第一次返回的Element再次使用xpath函数进行匹配,

但是需要注意的是

i.xpath(".//a/@href")需要加那个".",表示以当前元素为根节点,不然就会把从html根路径开始查找把所有的href都查出来了

如下如果不加"."得到的结果。

 

爬取天堂电影案例

# coding:utf-8
from lxml import etree
import requests

BASE_DOMAIN = "https://www.dy2018.com/"

url = "https://www.dy2018.com/html/gndy/dyzz/index_2.html"

proxy = {
    'http': '117.69.150.100:9000'  # 设置代理
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'

}


def get_detail_urls(url):
    response = requests.get(url, headers=headers, proxies=proxy)
    # requests库,默认会使用自己猜测的编码方式,将抓取下来的网页进行解码,然后存储到text属性。这里乱码我们需要自己指定解码方式
    # text = response.content.decode('gbk')
    text = response.text
    # with open('dianying.html','w',encoding='utf-8') as fb:
    #   fb.write(response.text)
    html = etree.HTML(text)
    detail_urls = html.xpath("//table[@class='tbspan']//a/@href")  # 获取a标签下的href属性
    # for detail_url in detail_urls:
    #   print(BASE_DOMAIN+detail_url)
    detail_urls = map(lambda url: BASE_DOMAIN + url, detail_urls)  # 使用无名函数,将列表中的每一项都执行一下函数。等价于下面的:
    # def abc(url):
    #   return BASE_DOMAIN+url
    # index = 0
    # for detail_url in detail_urls:
    #   detail_url = abc(detail_url)
    #  detail_urls(index) = detail_url
    #   index += 1
    return detail_urls


# 获取内容页数据
def parse_detail_page(url):
    response = requests.get(url, headers=headers)
    movie = {}
    # text = response.content.decode('utf-8')
    text = response.content.decode('gbk')
    html = etree.HTML(text)
    title = html.xpath("//div[@class='title_all']")
    # for x in title:
    #   print(etree.tostring(x,encoding='utf-8').decode('utf-8'))
    movie['title'] = title

    zoomE = html.xpath("//div[@id='Zoom']")[0]
    imgs = zoomE.xpath(".//img/@src")
    cover = imgs[0]
    screenshot = imgs[1]
    movie['cover'] = cover
    movie['screenshot'] = screenshot

    def parse_info(info, rule):
        return info.replace(rule, "").strip()

    infos = zoomE.xpath(".//text()")
    for index, info in enumerate(infos):
        if info.startswith("◎年  代"):
            info = info.replace("◎年  代", "").strip()  # 将年代字符串替换为空,strip方法去掉前后空格
            movie['year'] = info
        elif info.startswith("◎产  地"):
            info = parse_info(info, "◎产  地")
            movie['country'] = info
        elif info.startswith("◎类  别"):
            info = parse_info(info, "◎类  别")
            movie['category'] = info
        elif info.startswith("◎豆瓣评分"):
            info = parse_info(info, "◎豆瓣评分")
            movie['douban_rate'] = info
        elif info.startswith("◎片  长"):
            info = parse_info(info, "◎片  长")
            movie['duration'] = info
        elif info.startswith("◎导  演"):
            info = parse_info(info, "◎导  演")
            movie['director'] = info
        elif info.startswith("◎主  演"):
            info = parse_info(info, "◎主  演")
            actors = [info]
            for x in range(index + 1, len(infos)):  # 因为演员不止一个,所以要用遍历形式打印
                actor = infos[x].strip()
                if actor.startswith("◎"):
                    break
                actors.append(actor)
                movie['actors'] = actors
        elif info.startswith("◎简  介"):
            info = parse_info(info, "◎简  介")
            for x in range(index + 1, len(infos)):
                profile = infos[x].strip()
                movie['profile'] = profile
    down_url = html.xpath("//td[@bgcolor='#fdfddf']/a/@href")[0]
    movie['download_url'] = down_url
    return movie


# 获取列表数据:

def spider():
    base_url = "https://www.dy2018.com/html/gndy/dyzz/index_{}.html"
    movies = []
    for x in range(2, 9):  # 第一个for循环,用来控制电影共有7页
        url = base_url.format(x)
        # print(url)
        detail_urls = get_detail_urls(url)
        # url = "https://www.dy2018.com/html/gndy/dyzz/index_2.html"
        # detail_urls = get_detail_urls(url)
        for detail_url in detail_urls:  # 第二个for循环,用来遍历一页中所有电影的详情url
            # print(detail_url)
            movie = parse_detail_page(detail_url)
            movies.append(movie)
            print(movie)


if __name__ == '__main__':
    spider()

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姑苏冷

您的打赏是对原创文章最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值