之前按照别人的教程练习了一些爬取图片以及使用框架的实例,现在自己做图片的爬虫,内容为Leon Lai在豆瓣电影中的图片集,下载到本地保存,一共415张。
网页结构说明:
在图片集中可以轻松找到图片的链接地址,获取该地址保存即可。
网页每页显示30张图片,爬取415张图片,只需要在爬取一页完成后,修改start参数,每次加30重新进行请求即可。
一、使用scrapy框架
items.py,定义爬取的数据,存储图片的名称以及链接地址。
import scrapy
class LeonItem(scrapy.Item):
img_name = scrapy.Field()
img_url = scrapy.Field()
leon.py(spider)
注意:循环时,需要调用回调函数,重新对新的请求进行分析
# -*- coding: utf-8 -*-
import scrapy
from Leon.items import LeonItem
class LeonSpider(scrapy.Spider):
name = 'leon'
allowed_domains = ['movie.douban.com']
offset = 0
url = "https://movie.douban.com/celebrity/1036978/photos/?type=C&sortby=like&size=a&subtype=a&start="
start_urls = [url+str(offset)]
count = 1
def parse(self, response):
for each in response.xpath("//div[@class='cover']"):
item = LeonItem()
url = each.xpath("./a/img/@src").extract()[0]
item['img_url'] = url
item['img_name'] = 'p'+str(self.count)
self.count += 1
yield item
if self.offset<390:
self.offset += 30
yield scrapy.Request(self.url + str(self.offset), callback=self.parse)
pipelines.py
注意:使用scrapy的Request定义的是一个请求对象,其不含content属性,无法下载图片,所以使用requests库来获取图片并进行存储。
# -*- coding: utf-8 -*-
import scrapy
import time
import requests
class LeonPipeline(object):
def __init__(self):
self.path = r'D:\pic\images'
def process_item(self, item, spider):
print(item)
im = requests.get(item['img_url'])
fp = open(self.path + '\%s.jpg' % item['img_name'], 'wb')
fp.write(im.content)
fp.close()
setting.py
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134'
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
ITEM_PIPELINES = {
'Leon.pipelines.LeonPipeline': 300,
}
如果不设置user-agent则会产生403错误。
结果:
二、普通方法
from urllib.parse import urlencode
from requests.exceptions import RequestException
import time
import requests
from lxml import etree
#请求头文件
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134'
}
def get_page_index(offset):
#获取链接地址,使用字典的形式存储参数
data = {
'size': 'a',
'sortby': 'like',
'start': offset,
'subtype': 'a',
'type': 'C'
}
url = 'https://movie.douban.com/celebrity/1036978/photos/?'+urlencode(data)
try:
response = requests.get(url,headers=headers)
#请求成功
if response.status_code == 200:
return response.text #返回响应的内容
return None
except RequestException:
print('请求索引页出错')
return None
#解析index获取的响应内容,获取图片地址
def parse_page_index(html):
html = etree.HTML(html)
urls = html.xpath("//li/div[@class='cover']/a/img//@src")
for url in urls:
yield url
path = r'D:\pic\images'#r保持字符串的原始值,不进行转义
count = 1
def parse_page_detail(url):
im = requests.get(url,headers=headers)
global count
fp = open(path+'\%s.jpg'% str(count),'wb')
fp.write(im.content)
fp.close()
count += 1
def main(offset):
html = get_page_index(offset)
for url in parse_page_index(html):
parse_page_detail(url)
if __name__ == '__main__':
offset = 0
#改变offset的值,进行多页爬取
while offset<=390:
main(offset)
offset += 30
注意:因为感觉xpath比较好用,没有使用beautifulsoup,其实如果配合正则表达式的话也可以使用。
因为想统计图片的数量,并使用其对图片进行命名,计数变量必须是全局变量,但是又需要在函数中调用并改变数值,其方法是在函数中将其声明为全局变量。