前言
本次需要爬取二次元网站cos板块下的图片
需要用到request模块与lxml模块,所以请提前安装好这两个模块,打开cmd程序输入
request | lxml |
---|---|
pip install request | pip install lxml |
xpath解析
xpath解析:最常用最便捷高效的一种解析方式,通用性。
-xpath解析原理:
- 1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中
- 2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获
- 环境的安装:
- pip install lxml
- 如何实例化一个etree对象:from lxml import html etree = html.etree
- 1.将本地的html文档中的源码数据加载到etree对象中:
etree.parse(filePath)
- 2.可以将从互联网上获取的页面源码数据加载到该对象中
etree.HTML(‘page_text’)
- xpath(‘xpath表达式’)
- xpath表达式
- /:表示的是从根节点开始定位。表示的是一个层级
- //:表示的是多个层级,可以表示从任意位置开始定位
- 属性定位://div[@class=“song”] tag[@attrName=“attrValue”]
- 索引定位://div[@class=“fixedNav”]/div[2] 索引是从1开始的。
- 取文本:
- /text()获取的是标签中直系的文本内容
- //text()标签中非直系的文本内容(所有的文本内容)
- 取属性
- @attrName ==> div/@attrName
需求分析
首先打开网站,点击下一页,会发现网站的url是没有变化的
第一页:
第二页:
说明网站的内容是动态加载的,需要获取网站的ajax请求到的json数据,在网站页面点击鼠标右键,点击检查,在点击Network,最后点击XHR,这是用来获取ajax请求的。使其如下图一样
然后点击第二页,会有这样的请求
请求的url是:https://www.hmecy.com/wp-admin/admin-ajax.php?action=zrz_load_more_posts
请求方式的:post
请求携带的参数是:type: tag42,paged: 2
点击请求的Response,会发现请求返回信息中有一组html数据,这组html数据中就包含如下板块的内容
这样咱们就获取到了页面的信息
接下来随便点击一个标签,进入她的详情页,咱们要获取标题和下载图片,如图
你会发现它的图片都在id为‘content-innerText’的div中
标题在h1标签中
代码编写
首先导包
import requests
from lxml import html
import os
from multiprocessing.dummy import Pool
import time
本次需要用到三个函数
1、down_img
#下载图片的函数,使用多线程下载
def down_img(arr):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
}
content = requests.get(url=arr[1][0], headers=headers).content
with open(arr[0], 'wb')as fp:
fp.write(content)
print("下载完成一张")
time.sleep(0.3)
arr参数里面包含需要图片文件的路径和url网址,访问url得到其中的二进制数据,再将其下载到指定文件内
2、correct_title
#处理图片文件夹的标题
def correct_title(title):
error_set = ['/', '\\', ':', '*', '?', '"', '|', '<', '>']
for c in title:
if c in error_set:
title = title.replace(c, '')
return title
该函数用于纠正文件夹的标题,因为:
需要将获得的标题进行修改,将其中的非法关键词换为空
3、main
if __name__=="__main__":
start = time.time()
etree = html.etree
#ajax请求的url
url = 'https://www.hmecy.com/wp-admin/admin-ajax.php?action=zrz_load_more_posts'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
}
#所有图片的url链接储存在这里
all_url = []
if not os.path.exists('./erciyuan'):
os.mkdir('./erciyuan')
#下载前4页的图片,可以根据自己需要更改循环次数
for num in range(1,5):
data = {
'type': 'tag42',
'paged': str(num)
}
#获取请求到的json函数
response = requests.post(url=url,headers=headers,data=data).json()
#分析json函数,发现html代码在key为msg的value中
response = str(response['msg'])
tree = etree.HTML(response)
data_list = tree.xpath('//a[@class="link-block"]/@href')
for urls in data_list:
page_text = requests.get(url=urls,headers=headers).text
detail_tree = etree.HTML(page_text)
#获取标题
title = detail_tree.xpath('//*[@id="post-single"]/h1/text()')
#修改标题
titles = correct_title(str(title))
#存储的文件夹路径
paths = './erciyuan/' + str(titles)
url_list = detail_tree.xpath('//*[@id="content-innerText"]//img')
data_ins = []
i = 0
#创建文件夹
if not os.path.exists(paths):
os.mkdir(paths)
for ins in url_list:
#获取图片的url
data_url = ins.xpath('./@src')
#图片的存储路径
path = paths +'/'+ str(i) +'.jpg'
i=i+1
#将路径与图片的url存储到all_url中,方便后面使用多线程下载
all_url.append([path,data_url])
#创建4个线程
pool = Pool(4)
#将函数与all_url列表放入线程
pool.map(down_img,all_url)
print(time.time()-start)
访问ajax请求的url,传入对应的参数,若想访问其他板块,改变对应的参数即可,分析其中的json数据
html代码都在key为msg的value中,获取该信息,对其进行xpath解析,得到所有详情页对应的url
data_list = tree.xpath('//a[@class="link-block"]/@href')
访问详情页的url,再通过xpath解析,获取文章的标题和该页面的img列表
title = detail_tree.xpath('//*[@id="post-single"]/h1/text()')
url_list = detail_tree.xpath('//*[@id="content-innerText"]//img')
对列表进行循环
for ins in url_list:
#获取图片的url
data_url = ins.xpath('./@src')
#图片的存储路径
path = paths +'/'+ str(i) +'.jpg'
i=i+1
#将路径与图片的url存储到all_url中,方便后面使用多线程下载
all_url.append([path,data_url])
对img解析xpath解析,获取其中的src属性值,再给其一个存储路径,存储到all_url中
最后使用多线程进行下载。
总代码
import requests
from lxml import html
import os
from multiprocessing.dummy import Pool
import time
#下载图片的函数,使用多线程下载
def down_img(arr):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
}
content = requests.get(url=arr[1][0], headers=headers).content
with open(arr[0], 'wb')as fp:
fp.write(content)
print("下载完成一张")
time.sleep(0.3)
#处理图片文件夹的标题
def correct_title(title):
error_set = ['/', '\\', ':', '*', '?', '"', '|', '<', '>']
for c in title:
if c in error_set:
title = title.replace(c, '')
return title
if __name__=="__main__":
start = time.time()
etree = html.etree
#ajax请求的url
url = 'https://www.hmecy.com/wp-admin/admin-ajax.php?action=zrz_load_more_posts'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
}
#所有图片的url链接储存在这里
all_url = []
if not os.path.exists('./erciyuan'):
os.mkdir('./erciyuan')
#下载前4页的图片,可以根据自己需要更改循环次数
for num in range(1,5):
data = {
'type': 'tag42',
'paged': str(num)
}
#获取请求到的json函数
response = requests.post(url=url,headers=headers,data=data).json()
#分析json函数,发现html代码在key为msg的value中
response = str(response['msg'])
tree = etree.HTML(response)
data_list = tree.xpath('//a[@class="link-block"]/@href')
for urls in data_list:
page_text = requests.get(url=urls,headers=headers).text
detail_tree = etree.HTML(page_text)
#获取标题
title = detail_tree.xpath('//*[@id="post-single"]/h1/text()')
#修改标题
titles = correct_title(str(title))
#存储的文件夹路径
paths = './erciyuan/' + str(titles)
url_list = detail_tree.xpath('//*[@id="content-innerText"]//img')
data_ins = []
i = 0
#创建文件夹
if not os.path.exists(paths):
os.mkdir(paths)
for ins in url_list:
#获取图片的url
data_url = ins.xpath('./@src')
#图片的存储路径
path = paths +'/'+ str(i) +'.jpg'
i=i+1
#将路径与图片的url存储到all_url中,方便后面使用多线程下载
all_url.append([path,data_url])
#创建4个线程
pool = Pool(4)
#将函数与all_url列表放入线程
pool.map(down_img,all_url)
print(time.time()-start)