Python《使用lxml解析xpath–爬取konachan》

Python《使用lxml解析xpath–爬取konachan》今天尝试使用lxml来解析xpath的文档,其实也就是html文档了啦。一:lxml和xpathlxml库是一个XML、HTML的解析器,主要用于解析和提取XML、HTML数据。lxml库先将HTML文档解析,然后就可以使用XPath搜索或遍历HTML文档中的节点。首先得预先安装lxml,condainstalllxmlXPath是一门在XML文档中查找信息的语言。XPath可用来在XML文档中对元素和属性进行遍历,而将HTML文档转换成XML文档后,就可以用XPath

大家好,欢迎来到IT知识分享网。

今天尝试使用 lxml 来解析 xpath的文档,其实也就是html文档了啦。

一:lxml和xpath

lxml库是一个XML、HTML的解析器,主要用于解析和提取XML、HTML数据。lxml库先将HTML文档解析,然后就可以使用XPath 搜索或遍历HTML文档中的节点。
首先得预先安装lxml,conda install lxml

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历,而将 HTML文档转换成 XML文档后,就可以用 XPath 查找 HTML 节点或元素。

具体细节的用法和介绍呢,这些都是常识类的知识了,请参考https://www.jianshu.com/p/a7633dd72a3f 或者自行百度。

下面是一个简要的学习测试的例子:

from lxml import etree

# HTML字符串
text = ''' <bookstore> <book> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <name>杰克罗琳</name> <kep>aaa</kep> <kep>bbb</kep> <year>2005</year> <price>29.99</price> </book> </bookstore> '''

# 使用HTML()方法解析字符串
# HTML()默认使用的就是HTML解析器,如果遇到不规范的HTML代码,会自动补全。
html_element = etree.HTML(text)

# 解析后就可以调用xpath方法了,默认返回列表,空也是列表。
name = html_element.xpath('//book/name/text()') # 返回值:['杰克罗琳']
print(name)
name = html_element.xpath('//book/kep/text()') # 返回值:['aaa', 'bbb']
print(name)
name = html_element.xpath('//book/no/text()') # 返回值:[]
print(name)

二:爬取网站https://konachan.com/post

https://konachan.com/post 有很多很多动漫图片,包括很多YY的。
这不是重点,重点是我们今天需要做个小爬虫给它爬下来,尝试使用lxml的功能。

废话不多说,先来看看网站的首页,鉴于设计内容可能不良,因此我拿计算机遮盖了啊,自行查看。
在这里插入图片描述

我们再来看下url有啥特征呢。
https://konachan.com/post?page=3&tags=azur_lane
是由两部分组成,一个是页号,一个是标签,因此我们首先需要找到标签有哪些。

我们先去标签页去把所有的标签撸下来,这里是个分页,我们需要每个都访问下。
在这里插入图片描述

每个标签页,我们只保存有数据的标签次啊记录下来
在这里插入图片描述

有了标签,就进入该标签的页面
https://konachan.com/post? tags=azur_lane 是等于https://konachan.com/post?tags=azur_lane &page=1
因此只需要拼装页面即可访问到某个标签的某个分页面

到了具体的页面后呢。我们发现有超清大图的展示,因此我们直接抓取超清大图的链接。
在这里插入图片描述

按照习惯,我们先下载一个看看:
在这里插入图片描述

测试代码如下:

import requests

def run8():
    headers = { 
   
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
        "Referer": "https://konachan.com/"
    }
    with open("D:/estimages/mn.jpg", "wb") as f :
        f.write(requests.get("https://konachan.com/image/7c7f3625319166ecfb9a79895d020afd/Konachan.com%20-%20300620%20applekun%20blonde_hair%20fate_grand_order%20fate_%28series%29%20long_hair%20navel%20necklace%20ponytail%20ribbons%20saber%20saber_alter%20shorts%20sword%20weapon%20white%20yellow_eyes.jpg", headers=headers).content)
        f.close

if name == “main”: #主程序入口
run8() #调用上面的run方法

测试成功!
在这里插入图片描述

完整代码如下:
建立两个线程,一个线程专门去抓取标签,另一个专门去根据标签下载图片

import os
import requests
from bs4 import BeautifulSoup
from lxml import etree
import time
import threading

rootrurl = 'https://konachan.com/'
save_dir = 'D:/estimages/'
no_more_pages = 'END'
max_pages = 10

# 这是一个tag集合,tag不能重复
tag_cache = set()


headers = { 
   
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
    "Referer": "https://konachan.com/"
}

def getTotalPages(url):

    # 倒数第二个 <a>下面的<font><font>的text就是
    total_page_nums = 1
    html = BeautifulSoup(requests.get(url, headers=headers).text, features="html.parser")
    div = html.find('div', attrs={ 
   'class': 'pagination'})

    if div is not None:
        # 使用HTML()方法解析字符串
        # HTML()默认使用的就是HTML解析器,如果遇到不规范的HTML代码,会自动补全。
        html_element = etree.HTML(str(div))
        total_page_nums = int(html_element.xpath('//div/a/text()')[-2])

    return total_page_nums


def getOneTagPage(url):
    html = BeautifulSoup(requests.get(url, headers=headers).text, features="html.parser")
    trs = html.find('table', attrs={ 
   'class': 'highlightable'}).find('tbody').find_all('tr')

    for tr in trs:
        html_element = etree.HTML(str(tr))
        num = int(html_element.xpath('//tr/td/text()')[0])
        if num == 0:
            continue

        tag = html_element.xpath('//tr/td/a/@href')[1]
        if tag not in tag_cache:
            tag_cache.add(tag)


def getAllTags():
    url = rootrurl + 'tag?order=date'

    # Step 1: 获得总共多少页
    total_page_nums = getTotalPages(url)

    # Step 2: 自己构造页面爬取所有的tag
    for i in range(1, (total_page_nums + 1)):
    # for i in range(1550, (total_page_nums + 1)): # 为了测试方便, 直接从 1550页开始了。用户可以自行改回来,从第1页开始。
        print("tag page num : %d." % i)
        url = rootrurl + ('tag?order=date&page=%d' % i)
        getOneTagPage(url)


def saveOnePage(tag, idx, saveDir):
    url = rootrurl + tag[1:] + '&page=%d' % idx
    html = BeautifulSoup(requests.get(url, headers=headers).text, features="html.parser")
    a_s = html.find('ul', attrs={ 
   'id': 'post-list-posts'})
    if a_s is None:
        return
    a_s = a_s.find_all('a', attrs={ 
   'class': 'directlink largeimg'})

    i = 1
    for a in a_s:
        img_url = a.get('href')
        img = requests.get(img_url)  # 请求图片的实际URL
        with open(
                '{}/{}_{}.{}'.format(saveDir, idx, i, img_url.split(".")[-1]), 'wb') as jpg:  # 请求图片并写进去到本地文件
            jpg.write(img.content)
            i = i+1


def saveOneTag(tag):
    dir = '{}{}'.format(save_dir, tag.split("=")[-1])
    if not os.path.exists(dir):
        os.mkdir(dir)

    print(tag)
    url = rootrurl + tag[1:]
    tag_cache.remove(tag)  # 避免重复操作该 tag

    # Step 1: 获得总共多少页
    total_page_nums = getTotalPages(url)

    # Step 2: 便利每个页面进行下载
    for i in range(1, (total_page_nums + 1)):
        if i > 6:  # 此处纯属是为了方便测试,不然有的页面太多了啊
            break
        saveOnePage(tag, i, dir)





def saveAllTagImgs():

    # 临时得到一批 tag
    l = list(tag_cache)

    # 对每个tag进行访问操作
    for tag in l:
        saveOneTag(tag)



class myThread1 (threading.Thread):   #继承父类threading.Thread
    def __init__(self, threadID):
        threading.Thread.__init__(self)
        self.threadID = threadID

    def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
        print("Thread %d is running..." % self.threadID)
        getAllTags()
        print("Thread %d is over..." % self.threadID)

class myThread2 (threading.Thread):   #继承父类threading.Thread
    def __init__(self, threadID):
        threading.Thread.__init__(self)
        self.threadID = threadID

    def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
        print("Thread %d is running..." % self.threadID)
        while 1:
            time.sleep(5)  # wait to get all tags
            if len(tag_cache) == 0:
                break
            saveAllTagImgs()
        print("Thread %d is over..." % self.threadID)

if __name__ == '__main__':
    # get all tags
    # getAllTags()

    # get all imgs according to tags
    # saveAllTagImgs()
    # print(len(tag_cache))


    thread1 = myThread1(1)  # 创建多个线程去分别爬取各个标签页的数据
    thread1.start()

    thread2 = myThread2(2)  # 创建多个线程去分别爬取各个标签页的数据
    thread2.start()

    while 1:
        time.sleep(1)

效果如下:
在这里插入图片描述
在这里插入图片描述

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/22441.html

(0)
上一篇 2024-01-03 19:33
下一篇 2024-01-03 21:00

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信