动态网页抓取(使用多线程的方式采集某站4K高清壁纸(组图))

优采云 发布时间: 2022-03-12 23:14

  动态网页抓取(使用多线程的方式采集某站4K高清壁纸(组图))

  一、背景

  大家好,我是皮皮。对于不同的数据,我们采用不同的采集方式,图片、视频、音频、文字都是不同的。由于网站图片素材太多,今天我们采用多线程方式采集一站4K高清壁纸。

  二、页面分析

  目标网站:

  http://www.bizhi88.com/3840x2160/

  如图,有278页,这里我们抓取前100页的壁纸图片保存在本地;

  

  解析页面

  

  如图,鱼的图片在一个大盒子里( ),下面每个div对应一张高清壁纸;

  然后是各个页面的div标签中壁纸图片数据的各种信息:1.链接;2. 名称;下面是对xpath的分析;

  imgLink = each.xpath("./a[1]/img/@data-original")[0]

name = each.xpath("./a[1]/img/@alt")[0]

  有一个注意事项:

  图片标签既有src属性,也有data-original属性,都对应图片的url地址。我们一般使用后者,因为data-original-src是自定义属性,图片的实际地址,src属性要求页面完全加载。出现,否则不会得到对应的地址;

  三、采集想法

  上面说了,图片数据太多,我们不可能写一个for循环来一个一个下载,所以必须使用多线程或者多进程,然后把这么多的数据队列扔给线程用于处理的池或进程池;在python中,multiprocessing Pool 进程池,multiprocessing.dummy 非常好用,

  multiprocessing.dummy模块和multiprocessing模块的API是通用的;代码切换更灵活;

  页面网址规则:

  'http://www.bizhi88.com/s/470/1.html' # 第一页

'http://www.bizhi88.com/s/470/2.html' # 第二页

'http://www.bizhi88.com/s/470/3.html' # 第三页

  构造的网址:

  page = 'http://www.bizhi88.com/s/470/{}.html'.format(i)

  然后我们自定义了两个函数,一个是抓取和解析页面(spider),另一个是下载数据(download),打开线程池,使用for循环构建13个页面的url,存放在list中,作为一个url 队列,使用 pool.map() 方法进行爬虫和爬虫操作;

   def map(self, fn, *iterables, timeout=None, chunksize=1):

"""Returns an iterator equivalent to map(fn, iter)”“”

这里我们的使用是:pool.map(spider,page) # spider:爬虫函数;page:url队列

  功能:提取列表中的每一个元素作为函数的参数,一个一个地创建一个进程,放入进程池中;

  参数1:要执行的函数;

  参数2:迭代器,将迭代器中的数字作为参数依次传递给函数;

  四、数据采集

  导入相关第三方库

  from lxml import etree # 解析

import requests # 请求

from multiprocessing.dummy import Pool as ThreadPool # 并发

import time # 效率

  页面数据分析

  def spider(url):

html = requests.get(url, headers=headers)

selector = etree.HTML(html.text)

contents = selector.xpath("//div[@class='flex-img auto mt']/div")

item = {}

for each in contents:

imgLink = each.xpath("./a[1]/img/@data-original")[0]

name = each.xpath("./a[1]/img/@alt")[0]

item['Link'] = imgLink

item['name'] = name

towrite(item)

  下载下载图片

  def download_pic(contdict):

name = contdict['name']

link = contdict['Link']

with open('img/' + name + '.jpg','wb') as f:

data = requests.get(link)

cont = data.content

f.write(cont)

print('图片' + name + '下载成功!')

  main() 主函数

   pool = ThreadPool(6)

page = []

for i in range(1, 101):

newpage = 'http://www.bizhi88.com/s/470/{}.html'.format(i)

page.append(newpage)

result = pool.map(spider, page)

pool.close()

pool.join()

  阐明:

  在 main 函数中,我们更喜欢创建六个线程池;通过for循环动态构造100个url;使用map()函数对线程池中的url进行数据解析和存储操作;当线程池关闭时,线程池并没有关闭,只是将状态变为不能再次插入元素的状态;

  五、程序运行

  if __name__ == '__main__':

start = time.time() # 开始计时

main()

print(end - start) # 时间差

  结果如下:

  

  当然这里只截取了部分图片,一共爬取了2000+张图片。

  六、总结

  这次我们使用多线程爬取了一张壁纸网站的高清图片。如果我们使用requests,很明显同步请求和下载数据比较慢,所以我们使用多线程的方式下载图片,提高了爬取速度。以效率为例。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线