Python爬虫学习(一)
爬虫学习
目标:爬取壁纸并保存到本地 目标网站:http://desk.zol.com.cn/dongman/
(最后更改时间:2018/11/4)
要求
- 1.壁纸必须保存到脚本运行目录下的的 IMAGES文件夹内。
- 2.保存的图片必须以对应标题名和分辨率来命名,如:秋田君的小漫画 - 1920x1200.jpg。
- 3.图片分辨率应该是可选分辨率中最高的。
- 4.提示信息格式:正在下载 (下载数量):(图片名字)。
- 5.要有错误处理并给出相应提示,如:图片下载失败、网络超时的处理等。
要用到的Python库
- requests(需安装)
- os
- lxml中的etree(xpath)(需安装)
相关语法:
准备好这些以后,就可以开始写爬虫了
引入所需库文件
from lxml import etree
import requests
import os
设置头文件
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36',
}
写一个解析html的函数,参数为要获取的网址,返回值是解析后的,能用xpath进行定位的xml变量。
步骤:
- 使用requests中的get方法对网页进行请求,保存在变量r中
- 将r的编码方式设置为当前编码,防止乱码
- 使用etree.HTML()解析r.text(),保存在变量dom中
- 返回dom
def getText(url):
r = requests.get(url, headers = headers)
r.encoding = r.apparent_encoding
dom = etree.HTML(r.text)
return dom
目标是爬取图片,还需要一个能保存图片的函数:
保存图片与文字不太一样,需要将content(二进制)写入文件而不是text
使用open创建一个文件,因为命名需要使用名字-分辨率的格式来命名,所以我们使用name变量储存名字,px储存分辨率,所以除了将图片的url传入外,还要将这两个参数传进函数
使用f-string方法连接变量和字符串
def getImg(url, name, px):
r = requests.get(url, headers = headers)
if(r.status_code != 200):
print("图片下载失败")
return
r.encoding = r.apparent_encoding
f = open(f'{name}-{px}.jpg', 'wb')
f.write(r.content)
然后就是文件的保存位置问题,要求是IMAGES文件夹由脚本自动创建,没有就创建,否则不创建。
需要用到os库:
- 使用os.getcwd()函数得到脚本的工作路径,拼接字符串\IMAGES就得到了脚本工作目录下IMAGES文件夹的路径
- 使用os.path.exists(path)判断文件夹十分存在,不存在则创建
- 使用os.makedirs(path)创建文件夹
- 使用os.chdir将工作目录改为IMAGES文件夹下,即使图片保存到该文件夹
def createFileFolder():
path = os.getcwd() + "\IMAGES"
if not os.path.exists(path):
os.makedirs(path)
os.chdir(path)
准备工作完成
我们观察网页结构,发现需要爬取的壁纸共41页,每页的网址规律为:http://desk.zol.com.cn/dongman/x.html
x为页码数
所以写一个循环,次数为41,每次循环爬取当前页上的所有壁纸
firststep:获取图片名和组图链接
图片名在li标签下,属性值为class="photo-list-padding",使用xpath轻松得到图片名,总张数,时间,因为我们目标是爬取每组图片的第一张,所以有用信息只有图片名。组图链接在class="photo-list-padding"的li标签的href属性中,获取标签中的属性值可以在定位到该标签后使用//@'属性值'得到
secondstep:获取图片最高分辨率对应网址和最高分辨率
同理可以发现分辨率在dd标签下的a标签的id属性中,而图片链接则在href属性中。
注意:有个严重的问题,从第二页壁纸开始,有一些壁纸不提供下载服务,这些图片的分辨率在网页中找不到,而且也无法获取像其他图片那样获取图片链接,但这类图片在网页中还有个展示的图片,分辨率均为960x600,对应网址都在img标签中的src属性中,分两种情况讨论,程序才不会报错,否则会报错提示分辨率对应的列表为空!
thirdstep:下载图片
一切都准备好了,写个循环使用getImg()下载图片即可,别忘了打印提示信息
最后附上完整代码
from lxml import etree
import requests
import os
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36',
}
def getText(url):
r = requests.get(url, headers = headers)
r.encoding = r.apparent_encoding
dom = etree.HTML(r.text)
return dom
def getImg(url, name, px):
r = requests.get(url, headers = headers)
if (r.status_code != 200):
print("图片下载失败")
return
r.encoding = r.apparent_encoding
f = open(f'{name}-{px}.jpg', 'wb')
f.write(r.content)
def createFileFolder():
path = os.getcwd() + "\image"
if not os.path.exists(path):
os.makedirs(path)
os.chdir(path)
def getImgName_href(dom):#得到图片名和图片详细链接
name = dom.xpath('//li[@class="photo-list-padding"]//em//text()')
href = dom.xpath('//li[@class="photo-list-padding"]//@href')
return name, href
def getImgHref_Px(href):#得到最高分辨率图片地址和最高分辨率
dom = getText(href)
try:
px = dom.xpath('//dd[@id="tagfbl"]//a//@id')[0]
imgUrl = dom.xpath('//dd[@id="tagfbl"]//a[@target="_blank"]//@href')[0]
dom_1 = getText(host + imgUrl)
imgHref = dom_1.xpath('//img//@src')[0]
return imgHref, px
except:
imgHref = dom.xpath('//div[@id="mouscroll"]//img//@src')[0]
return imgHref, "960x600"
host = "http://desk.zol.com.cn"
target = "http://desk.zol.com.cn/dongman/"
cnt = 0
createFileFolder() # 创建文件夹并将图片下载换到image
for x in range(1, 42):
dom = getText("http://desk.zol.com.cn/dongman/" + str(x) + ".html")
name, href = getImgName_href(dom)
for i in range(0, len(href)): # 下载壁纸QAQ
cnt = cnt + 1
print("正在下载" + str(cnt) + ":" + name[i])
imgHref, px = getImgHref_Px(host + href[i])
getImg(imgHref, name[i], px)