大家好,欢迎来到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