最近正在参加单位组织的FineReport报表编程培训,对于帆软提出的“无码编程”的理念,实在是让我无感,我想对于每一个编程爱好者来说,敲代码给我们带来的乐趣,不用我多说大家都有深刻的体会。所以就在培训时开了个小差,写了个简单的爬虫练习,爬取《视觉中国设计师社区》编辑推荐的图片。下面附上网站爬虫的分析思路和代码。
1.网站爬取分析思路:
(1)登录网站:
(2)通过向下滚动鼠标,发现不断有新的图片集加载出来,而URL没有变化,所以分析网站是采用异步加载的方式,读取的图片数据。
(3)点击F12查看网页加载过程,发现动态加载数据的URL地址链接(如图)。
通过上图可以看出随着鼠标的向下拖动,不断有新的链接加载出来,判断这些链接中将会的包含每个图片集的URL,点击其中一个图片集。
发现网页URL链接后的字符串,同异步加载返回的json数据中的id键对应的值相同,所以可以在从json数据中提出id键对应的值,来构造每个图片集的URL链接,进行对每个图片集的访问。同时也发现每个图片集的名称同json数据中title键对应的值相同,所以可以提取到每个title键对应的值,用于以后用图片集名称来建立每个独立文件夹来存储图片。
(4)通过查看异步加载返回的json数据,发现当加载到下图的链接https://www.shijue.me/community/search?type=json&page=12&size=20&license=-1&orderby=recommendTime时返回的json数据为null,判断已经无数据再异步加载回来,所以可以确定所需构建的数量。
(5)我们的目的是要获取到每个图片集中的具体图片,并以图片集名称建立文件夹分别储存,所以这一步要通过访问没给图片集的URL,来获取到每张图片的URL,从而回去到图片保存至本地。访问图片集的URL后,在网页的源码中查找每张图片的URL。
通过上图发现每张图片的URL都隐藏在网页源码javascrapt代码中,所以我将使用正则表达式来匹配得到每个图片的URL,进而得到图片。
2.爬虫代码及注释解析:
import requests
from bs4 import BeautifulSoup
import json
from pathlib import Path
import re
class ShijueSpider():
def __int__(self):
pass
#请求URL的类方法
def request(self,url):
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3135.4 Safari/537.36'
}
return requests.get(url,headers=headers)
#创建存储路径的文件夹的类方法
def create_dir(self,name):
directory = Path(name)
if not directory.exists():
directory.mkdir()
return directory
#获取图片链接地址的类方法
def get_photo(self):
#创建图片的存储文件夹
root_dir = self.create_dir('./视觉中国')
#循环构建网页异步请求数据的URL,并请求
for i in range(1,12):
url = 'https://www.shijue.me/community/search?type=json&page='+str(i)+'&size=20&license=-1&orderby=recommendTime'
json_str = self.request(url).text
#利用json.load函数将请求的数据转换成字典类型
ids = json.loads(json_str)
#循环得到每个图片集名称和图片集的URL
for i in range(1,len(ids['dataArray'])):
#将图片集名称赋值给变量album_name
album_name = ids['dataArray'][i]['title']
#正则过滤掉了标题中在 windows 下无法作为目录名的特殊字符
album_name = re.sub(r'[\\/:*?"<>|]', '', album_name)
#在视觉中国文件夹下以图片集名称分别存储图片的子文件夹
dir_name = self.create_dir(root_dir / album_name)
#构建图片集的URL
url_id = "https://www.shijue.me/community/photo-details/"+ids['dataArray'][i]['id']
html = self.request(url_id).text
#正则匹配图片集中每张图片的URL,返回列表
pattern = re.compile(r"http://img\.shijue\.me/.{30,50}!dp5")
response = pattern.findall(html)
i = 1
for res_url in response:
#从图片的URL中提取图片的后缀名并给图片的名称编号
photo_name = str(i) + res_url[-9:-4] if res_url[-8:-4] == 'jpeg' else str(i) + res_url[-8:-4]
try:
#调用下载并保存图片的类的方法(传入的参数为图片的URL,图片的名称及储存路径)
self.save_photo(res_url,photo_name,dir_name)
except:
continue
i+=1
#保存图片文件的类方法
def save_photo(self,url,photo_name,save_dir):
data = self.request(url)
save_path = save_dir / photo_name
fp = open(save_path,'wb')
fp.write(data.content)
fp.close()
if __name__=="__main__":
#实例化ShijueSpider()爬虫的类
shijue = ShijueSpider()
#调用累的get_photo()方法
shijue.get_photo()
3.爬取完成效果展示: