page contents

python并发实现抓取彼岸图片网

python并发实现抓取彼岸图片网 目标网址:http://pic.netbian.com/ 需求:1.至少要保存1000张图片2.不能出现重复的图片3.保存的图片文件名要以网站中所给的图片名命名4.请以面向对象的方式实...

python并发实现抓取彼岸图片网

目标网址:http://pic.netbian.com/

需求:1.至少要保存1000张图片2.不能出现重复的图片3.保存的图片文件名要以网站中所给的图片名命名4.请以面向对象的方式实现5.所有的图片请单独存放在同一个文件夹中

(一)分析目标网址

1.目标网页每页20张图片,需要获取1000张图片则需要翻页

第一页网址:https://pic.netbian.com/index.html

第二页网址:https://pic.netbian.com/index_2.html

第三页网址:https://pic.netbian.com/index_3.html

观测每一页的网址发现除了第一页index后不带数字,其他页面index后面的数字都是对应的页码

2.不能出现相同的图片,这里使用图片名称来判断,如果图片名称一样,则判断图片一样,不重复下载。

3.网页中开发目标网址,获取图片名称

4.使用python创建一个面向目标网址的类,及写入获取目标图片的方法

5.使用os库来创建一个文件夹

(二)获取目标位置

1.在网页地址栏输入目标网址,打开网页;

2.按下F12打开开发者工具,下图中红色部分;

3.鼠标点击资源定位符然后点击需要定位的图片,如

定位到目标位置

在这就可以获取到图片网址(src,注意网址不全需要拼接)和名称(<b>标签里),通过xpath就可以提取出来;

4.通过下载发现用src下载的图片分辨率比较小

5.点击进入目标图片的二级目录,并按F12打开开发者工具,资源定位符点击目标图片,发现二级目录下也有个src,且与一级目录的不一样;

6.点击进入图片的三级目录,发现是我们需要的图片网址。

(三)python代码实现

1.定义一个爬虫类,及方法

class BiAn(object):

def init(self):

# 获取二级网址

def get_href(self):

# 获取图片网址

def get_img_url(self, title, href):

# 对所有图片详细网址并发请求的方法

def concurrency(self):

# 需要并发的请求方法

async def requests(self, title, img_url):

# 保存图片的方法

def save_img(self, title, content):

# trunc方法

def trunc(self):

2. init

# 当前文件夹如果没有picture文件夹,就创建picture文件夹
if not os.path.exists('./picture'):
  os.mkdir('./picture')

# 收集所有的图片信息,这里为图片名和图片网址
self.img_info = []

# 输入需要爬取的页数
self.page = int(input('请输入需要爬取的页数:'))

# 彼岸网址,需要个请求头就行
self.headers = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}

3.获取所有图片的二级目录网址

for i in range(1, self.page+1):

  # 第一页的网址区别于其他页,直接if判断
if i == 1:
url = 'https://pic.netbian.com/index.html'
else:
url = f'https://pic.netbian.com/index_{i}.html'

  # 对一级网址发起请求
  response = requests.get(url=url, headers=self.headers).text.encode('iso-8859-1').decode('gbk')

  # 使用etree解析目标网址
  tree = etree.HTML(response)

  # 获取图片列表信息
  li_list = tree.xpath('//div[@id="main"]/div[3]/ul/li')

  # 遍历图片列表信息
  for li in li_list:

     # 获取单张图片名称 有些页面title在b标签下的便签里,所以要用//
     title = li.xpath('./a/b//text()')[0]

     # 获取图片二级网址地址
     href = 'http://pic.netbian.com' + li.xpath('./a/@href')[0]

     # 调用get_img_url
     self.get_img_url(title, href)

4.获取图片的三级目录网址(及分辨率较高的图片网址)

# 对二级网址发起请求
response = requests.get(url=href, headers=self.headers).text

# 使用etree解析目标网址
tree = etree.HTML(response)

# 获取图片详细网址,获取到的网址不全需要拼接
img_url = 'http://pic.netbian.com' + tree.xpath('//*[@id="img"]/img/@src')[0]

# 将名称和网址封装在一个字典中
item = {
  'title': title,
  'url': img_url
}

# 图片的信息添加到列表中
self.img_info.append(item)

5.并发及一级获取图片二进制数据

def concurrency(self):

  # 定义一个任务列表
  stasks = []

  # 遍历所有的图片网址
  for url in self.img_info:

     # 调用requests方法
     c = self.requests(url['title'], url['url'])

     # 封装任务
     task = asyncio.ensure_future(c)

     # 添加到任务列表
     stasks.append(task)

  # 创建一个协程任务对象
  loop = asyncio.get_event_loop()

  # 将任务列表封装到wait中
  loop.run_until_complete(asyncio.wait(stasks))

# 需要并发的请求方法
async def requests(self, title, img_url):

  # 请求图片网址获取二进制数据
  content = requests.get(url=img_url, headers=self.headers).content

  # 调用save_img方法用于保存图片
  self.save_img(title, content)

6.保存图片

def save_img(self, title, content):

  # 以二进制的方式打开一个jpg文件
  with open(f'./picture/{title}.jpg', 'wb')as fp:

     # 将二进制数据写入打开的jpg文件
     fp.write(content)

     # 关闭文件
     fp.close()

  # 输出提示信息
  print(f'{title}下载完成')

(四)小tips

1.第一页的网址并不是https://pic.netbian.com/index_1.html

而是https://pic.netbian.com/index.html,所以第一页要特殊处理,使用if判断,如果是第一页,直接定义url='https://pic.netbian.com/index.html',其他页码就用f格式化;

2.获取图片名称时不能再a标签里@title提取,因为第二页a便签就没有title属性了,会获取不到图片名称

而要在a标签的b便签下获取 文本属性

3.获取图片名称时response = requests.get(url=url, headers=self.headers).text,若果没有对中文进行编转码,就会获取到乱码

,解决方法

response = requests.get(url=url, headers=self.headers).text.encode('iso-8859-1').decode('gbk')

4. 二级和三级目录的网址都需要拼接

href = 'http://pic.netbian.com' + li.xpath('./a/@href')[0]
img_url = 'http://pic.netbian.com' + tree.xpath('//*[@id="img"]/img/@src')[0]

5.爬多了会被反爬,最好把cookie加上

(五)完整代码

# 定义一个爬虫类
class BiAn(object):

  def __init__(self):

     # 当前文件夹如果没有picture文件夹,就创建picture文件夹
     if not os.path.exists('./picture'):
        os.mkdir('./picture')

     # 收集所有的图片信息,这里为图片名和图片网址
     self.img_info = []

     # 输入需要爬取的页数
     self.page = int(input('请输入需要爬取的页数:'))

     # 彼岸网址,需请求头,最好把cookie加上
     self.headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
    }

  # 获取图片子网址的方法
  def get_href(self):

     # 遍历每一页网址
     for i in range(1, self.page+1):
       
# 提示信息
print(f'正在获取第{i}页的信息。。。')

        # f格式化网址
        if i == 1:
           url = 'https://pic.netbian.com/index.html'
        else:
           url = f'https://pic.netbian.com/index_{i}.html'

        # 对一级网址发起请求
        response = requests.get(url=url, headers=self.headers).text.encode('iso-8859-1').decode('gbk')
        print(response)
        # 使用etree解析目标网址
        tree = etree.HTML(response)

        # 获取图片列表信息
        li_list = tree.xpath('//div[@id="main"]/div[3]/ul/li')

        # 遍历图片列表信息
        for li in li_list:

           # 获取单张图片名称
           title = li.xpath('./a/b/text()')[0]

           # 获取图片二级网址地址
           href = 'http://pic.netbian.com' + li.xpath('./a/@href')[0]

           # 调用get_img_url
           self.get_img_url(title, href)

  # 从二级网址获取图片详细网址
  def get_img_url(self, title, href):

     # 对二级网址发起请求
     response = requests.get(url=href, headers=self.headers).text

     # 使用etree解析目标网址
     tree = etree.HTML(response)

     # 获取图片详细网址,获取到的网址不全需要拼接
     img_url = 'http://pic.netbian.com' + tree.xpath('//*[@id="img"]/img/@src')[0]

     # 将名称和网址封装在一个字典中
     item = {
        'title': title,
        'url': img_url
    }

     # 图片的信息添加到列表中
     self.img_info.append(item)

  # 对所有图片详细网址并发请求的方法
  def concurrency(self):

     # 定义一个任务列表
     stasks = []

     # 遍历所有的图片网址
     for url in self.img_info:

        # 调用requests方法
        c = self.requests(url['title'], url['url'])

        # 封装任务
        task = asyncio.ensure_future(c)

        # 添加到任务列表
        stasks.append(task)

     # 创建一个协程任务对象
     loop = asyncio.get_event_loop()

     # 将任务列表封装到wait中
     loop.run_until_complete(asyncio.wait(stasks))

  # 需要并发的请求方法
  async def requests(self, title, img_url):

     # 请求图片网址获取二进制数据
     content = requests.get(url=img_url, headers=self.headers).content

     # 调用save_img方法用于保存图片
     self.save_img(title, content)

  # 保存图片的方法
  def save_img(self, title, content):

     # 以二进制的方式打开一个jpg文件
     with open(f'./picture/{title}.jpg', 'wb')as fp:

        # 将二进制数据写入打开的jpg文件
        fp.write(content)

        # 关闭文件
        fp.close()

     # 输出提示信息
     print(f'{title}下载完成')

  # __trunc__方法
  def __trunc__(self):
     self.get_href()


# 实例化一个BiAn类的对象
bian = BiAn()

# 计时器,开始时间点
star_tiem = time.time()

# 调用__trunc__方法程序执行,获取到图片信息,并存储在self.img_info里
bian.__trunc__()

# 调用concurrency方法来实现并发,节省运行时间
bian.concurrency()

# 看一下程序运行用了多长时间
print(time.time()-star_tiem)
  • 发表于 2022-07-24 11:45
  • 阅读 ( 744 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
钟孝武
钟孝武

3 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1470 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章