静态页面抓取实战
目标:美图吧–风景类图片
有多个页面,分析各页面url:
页面序号随url最后一位数变换,第一页为1,第二页为2……找出规律后设定循环来进行循环访问个页面
右键点击图片检查:
每一张图片都有一个超链接(href),点击超链接进入
进入超链接页面即可得到展示图片的页面;同时每一组页面有多张图片,每张图片都有一个超链接,经过测试发现这个超链接(href)是同组图片中的下一涨图片的页面url;(src)就是图片的路径地址。src就是我的目标,通过得到这个src的值去访问图片路径地址,然后将图片下载下来
在测试时发现一个问题,就是每一组的最后一张图片的href都是直接访问到另一个图片组的。为了逻辑处理上的方便,在进行爬取之前做个小处理: 在进入图片组页面之后,先获取这个图片组的图片张数,通过图片的数量控制在图片组中停留的次数,同时也避免因为通过最后一张图片的href直接进入到下一组图片,造成数据的混乱(原则上是可以直接通过每组图片最后一张图片的href直接进入到下一组图片的。但是弊端就是无法判断你是否把这一类别的数据获取完了)
至此这个静态页面抓取的思路就成型了。
下面直接挂上代码:
import requests
import os
from bs4 import BeautifulSoup
import re
url = 'http://www.meituba.com/weimei/fjtp/list114{}.html'
# 因为url最后一个数是随页面序号变化的,因此用{}进行占位,在调用url时再传入页面序号去进行访问
ppho_url = 'http://www.meituba.com/weimei/fjtp/'
# 对于小网站可以不设headers,为了严谨一点,此案例加上headers
HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)'
' Chrome/79.0.3941.4 Safari/537.36'}
# 解析器
def parser(url):
# 建立请求 返回请求对象
response = requests.get(url, headers=HEADERS)
# 转码
html = response.content.decode('utf-8')
# 对转码后的网页信息进行解析(规范化)
soup = BeautifulSoup(html, 'lxml')
# 返回解析后的对象
return soup
"""
pageNum为测试代码的参数,实际情况可以不设参数,直接通过条件判断对页面遍历到底,也可以通过参数指定要爬取的页数
"""
def crawling(pageNum):
# 设定循环页面
for i in range(1, pageNum + 1):
response = parser(url.format(i))
# 得到照片组的html并解析
group_pho_htmls = response.find_all('a', target="_blank")
original_group_pho_urls = []
# 遍历照片组的解析html,并依次提取url并存储到列表中
for group_pho_html in group_pho_htmls:
original_group_pho_urls.append(group_pho_html["href"])
# 得到的original_group_pho_urls有重复,为节省资源,进行一步去重
group_pho_urls = []
for original_group_pho_url in original_group_pho_urls:
if original_group_pho_url not in group_pho_urls:
group_pho_urls.append(original_group_pho_url)
# 依次遍历每个图片组的路径并解析
for group_pho_url in group_pho_urls:
response = parser(group_pho_url)
# 获取当前照片组的图片张数
num_control = response.find_all('div', class_="pages")
control_num = re.search('[0-9]', str(num_control))
# 获取当前zu照片的路径
pho_htmls = response.select('body > div.main21 > div.main > div.photo > a')
pho_html = pho_htmls[0]["href"]
# 由于一个组有多张照片 对pho_url进行拆分匹配
pho_html = str(pho_html).split('_')[0]
for i in range(1, int(control_num.group()) + 1):
if i == 1:
pho_hhtml = ppho_url + '/' + str(pho_html) + '.html'
print(pho_hhtml)
response = parser(pho_hhtml)
pho_url_s = response.select('body > div.main21 > div.main > div.photo > a > img')
pho_url = pho_url_s[0]["src"]
else:
pho_hhtml =ppho_url + '/' + str(pho_html) + '_' + str(i) + '.html'
print(pho_hhtml)
response = parser(pho_hhtml)
pho_url_s = response.select('body > div.main21 > div.main > div.photo > a > img')
pho_url = pho_url_s[0]["src"]
# 拆分url 根据url命名文件
dir_name = pho_url_s[0]["alt"]
file_name = str(pho_url).split('/')[-1]
# 将图片写入文件中
try:
if not os.path.exists("./" + str(dir_name)):
os.mkdir("./" + str(dir_name))
if not os.path.exists("./" + str(dir_name) + '/' + file_name):
with open("./" + str(dir_name) + '/' + file_name, 'wb') as p:
p.write(requests.get(pho_url, headers=HEADERS).content)
except :
print("发现了错误 跳过")
i += 1
# 如果已经获取到本组最后一张图片,就退出循环
if i == int(control_num.group()) + 1:
break
if __name__ == '__main__':
crawling(2)