返回介绍

4.3 下载房源图片和实现多线程爬虫

发布于 2025-04-21 19:15:26 字数 4091 浏览 0 评论 0 收藏

4.3.1 下载房源图片

爬虫实战-多线程和图片下载

这一节接着前面介绍爬取 Q 房网的例子来讲解如何下载图片和实现多线程爬虫。

现在希望下载二手房房源的图片。为了简单讲解,仅下载二手房列表页的展示图,也就是图 4-7 中左侧的小图片。

图 4-7 二手房房源信息

要下载图片,首先需要获取图片的 URL,其次请求这个 URL 获得图片内容,最后保存图片,下面用代码来演示。在上节 spider 函数代码中的 for 循环里增加如下代码。

#首先解析出图片的 URL
image_url = house.xpath('a/img/@data-original')[0] 
#下载图片 
img = requests.get(image_url, headers=headers) 
with open('./Qfang_image/{}.jpg'.format(apartment), 'wb') as f: 
    f.write(img.content)  #保存图片 
... 

在这里首先使用 XPath 路径获取图片的 URL,然后使用 requests.get 获取这张图片,最后新建了一张图片并把获取的图片保存起来。这里把获取到的图片保存在了当前程序运行目录下的 Qfang_image 文件夹里,并使用图片所属房源标题作为保存图片的名称。

以上就是下载图片的代码,比较简单,读者要注意给图片起个合适的名字,防止重名。

4.3.2 实现简单多线程爬虫

有时候会遇到爬虫的爬取速度太慢的情况,如上面抓取房源图片会大大降低爬虫的速度。这时可以通过使用多线程来加快爬取速度。下面介绍如何实现一个多线程的 Python 爬虫来提高爬虫的效率。

1. 基本知识

多进程和多线程在大部分情况下都能加快处理效率,缩短处理时间,但是会出现通信、数据共享及加锁问题等。为了降低使用门槛,可以使用 Python 的标准库 multiprocessing 模块,这个模块让人们很容易利用多进程和多线程来处理任务。

那么应该使用多进程还是多线程呢?一般计算(CPU)密集型任务适合多进程,IO 密集型任务适合多线程。所谓 IO 密集型任务,就是类似网络交互、文件读写、网络爬虫等任务,这些任务不依赖 CPU 的操作,因此可以通过使用多线程来大大提高爬虫程序的效率。

2. 线程实现

下面重点讲解与爬虫有关的线程池的用法。

首先了解一下线程实现的基本步骤。

(1)从 multiprocessing.dummy 导入线程池。

(2)创建一个线程池,完成对线程的初始化创建工作。

(3)把任务交给线程池。

(4)调用 join 方法等待这个线程结束工作。

下面使用多线程来实现 Q 房网二手房房源爬虫。

第一步,导入线程池和其他库。给导入的线程池起一个别名 pl。

from multiprocessing.dummy import Pool as pl
from lxml import etree 
import requests 
import csv 
 
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) \ 
           AppleWebKit/537.36 (KHTML, like Gecko) \ 
           Chrome/46.0.2490.80 Safari/537.36'} 
pre_url = 'http://shenzhen.qfang.com/sale/f' 

第二步,定义下载函数。

def download(url):
    html = requests.get(url, headers=headers) 
return etree.HTML(html.text) 

第三步,定义数据写入函数。

def data_writer(item):
    with open('qfang_ershoufang.csv', 'a',  
              encoding='utf-8', newline='') as csvfile: 
        writer = csv.writer(csvfile) 
writer.writerow(item) 

第四步,定义图片保存函数 image_saver。

def image_saver(url, xiaoqu):
    img = requests.get(url, headers=headers) 
    with open('./Qfang_image/{}.jpg'.format(apartment), 'wb') as f: 
f.write(img.content) 

第五步,定义爬取函数 spider。

def spider(url):
    selector = download(url) 
    house_list = selector.xpath("//*[@id='cycleListings']/ul/li") 
    for house in house_list: 
        apartment = house.xpath("div[1]/p[1]/a/text()")[0] 
        house_layout = house.xpath("div[1]/p[2]/span[2]/text()")[0] 
        area = house.xpath("div[1]/p[2]/span[4]/text()")[0] 
        region = house.xpath("div[1]/p[3]/span[2]/a[1]/text()")[0] 
        total_price = house.xpath("div[2]/span[1]/text()")[0] 
        #构造详情页 URL 
        house_url = ('http://shenzhen.qfang.com' 
                     + house.xpath("div[1]/p[1]/a/@href")[0]) 
        sel = download(house_url) 
        house_year = sel.xpath("//div[@class='housing-info']/ul/li[2]" 
                               "/div/ul/li[3]/div/text()")[0] 
        mortgage_info = sel.xpath("//div[@class='housing-info']/ul/li[2]" 
                                 "/div/ul/li[5]/div/text()")[0] 
        item = [apartment, house_layout, area, region,  
                total_price, house_years, mortgage_info] 
        data_writer(item) 
        print('正在抓取', xiaoqu) 
        image_url = house.xpath('a/img/@data-original')[0] 
image_saver(image_url, xiaoqu) 

第六步,编写主程序、初始化线程池。

if __name__ == '__main__':
pool = pl(4)     # 初始化线程池 

初始化线程池有个参数,可以根据计算机的 CPU 核心数填写。例如计算机是四核的,这里就填写 4。

用列表推导式生成要爬取的页面 URL 列表,例如总共要爬取 99 页。

house_url = [pre_url+str(x) for x in range(1, 100)] 

下面使用线程池的 map 方法对要爬取的页面执行 spider 函数,线程池的 map 方法与 Python 中的 map 方法使用方式基本相同。

pool.map(spider, house_url) 

最后关闭线程池并等待所有线程结束。

pool.close()
pool.join() 

这样就完成了整个多线程爬虫的编写。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。