对于熟悉爬虫领域的程序员应该都知道爬取网站图片有简单的几个步骤:获取网页源码、审阅元素寻找所需信息、下载并保存到指定位置。
因为本爬虫系列曾爬取过头条上的图,大部分步骤雷同,这里主要是针对反爬与反反爬进行拓展,采取模块化的思路进行程序文档编写。
首先,主函数目的就是下载并保存目标图片:
if __name__ == '__main__':
download_img()
time.sleep(5)#停止一会,防止频率过快被封IP或账号
主函数中的download_img()函数需要如下代码中的几个步骤。按照模块化的思路,定义get_page函数、find_imgs函数和save_img函数,使得函数框架更加的清晰。
def download_img(folder = 'ooxx',pages = 10):
#包含两个参数:目标文件夹;爬取的页面数量
os.mkdir(folder)
os.chdir(folder)
#创建文件夹到目标路径并改变当前工作目录到指定的路径
url = 'http://jandan.net/ooxx/'
#待爬取网站的url
page_num = int(get_page(url))
#根据url获取当前页码,并改为整形赋值给page_num
for i in range(pages):
page_num -= i
page_url = url+ 'page-' + str(page_num) + '#comments'
#图片所在页面的url
img_addrs = find_imgs(page_url)
#根据url找到图片,保存在img_addrs列表中
save_img(folder, img_addrs)
#保存列表中的图片到指定目标路径下的文件夹
接下来就该写的是几个自定义函数了,而在get_page函数和save_img函数中都需要读取url,获取信息。所以考虑到代码精简,再定义个子函数url_open()。如下代码所示:
def url_open(url):
req = urllib.request.Request(url)
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36')
# ~ proxies = ['125.120.201.62:808',
# ~ '183.159.91.240:18118',
# ~ '171.12.182.238:26316',
# ~ ]
# ~ proxy = random.choice(proxies)
# ~ proxy_support = urllib.request.ProxyHandler({'http':proxy})
# ~ opener = urllib.request.build_opener(proxy_support)
# ~ urllib.request.install_opener(opener)
response = urllib.request.urlopen(url)
html = response.read()
return html
下边是download函数里需要调用的三个自定义子函数:
def get_page(url):
# 返回页面
html = url_open(url).decode('utf-8')
a = html.find('current-comment-page') + 23
# 返这里没有用正则表达式,采用find方法查找信息
# 23和下边的9,4都是偏移量(自己在网页上审阅元素数即可)
b = html.find(']',a)
return html[a:b]def find_imgs(page_url):
url_open(url).decode('utf-8')
img_addrs = []
a = html.find('img src=')
while a != -1:
b = html.find('.jpg',a,a+255)
#限制b的范围
#找不到jpg(因为存在gif的情况)即b返回-1
if b != -1:
img_addrs.append(html[a+9:b+4])
else:
b = a + 9
a = html.find('img src=',b) #起始于b
for each in img.addrs:
print(each)
def save_img(folder, img_addrs):
for each in img_addrs:
filename = each.split('/')[-1]
#分离出最后一个‘/’后的内容作为名称
with open(filename,'wb') as f:
img = url_open(each)
f.write(img)