本文先熟悉并发与并行、阻塞与非阻塞、同步与异步、多线程、多线程、协程的基本概念。再实现asyncio + aiohttp爬取链家成都二手房源信息的异步爬虫,爬取效率与多线程版进行简单测试和比较。

1. 基本概念

并发与并行

  • 并发: 指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。
  • 并行: 指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。

阻塞与非阻塞

  • 阻塞状态指程序未得到所需计算资源时被挂起的状态。程序在等待某个操作完成期间,自身无法继续处理其他的事情,则称该程序在该操作上是阻塞的。
  • 非阻塞:程序在等待某操作过程中,自身不被阻塞,可以继续处理其他的事情,则称该程序在该操作上是非阻塞的。

同步与异步

  • 同步:不同程序单元为了完成某个任务,在执行过程中需靠某种通信方式以协调一致,我们称这些程序单元是同步执行的。
  • 异步:为完成某个任务,不同程序单元之间过程中无需通信协调,也能完成任务的方式,不相关的程序单元之间可以是异步的。

多线程
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。

多进程
多进程(multiprocessing),每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行,也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。多进程就是利用 CPU 的多核优势,在同一时间并行地执行多个任务,可以大大提高执行效率。

协程
协程,英文叫作 Coroutine,又称微线程、纤程,协程是一种用户态的轻量级线程。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此协程能保留上一次调用时的状态,即所有局部状态的一个特定组合,每次过程重入时,就相当于进入上一次调用的状态。协程本质上是个单进程,协程相对于多进程来说,无需线程上下文切换的开销,无需原子操作锁定及同步的开销,编程模型也非常简单。我们可以使用协程来实现异步操作,比如在网络爬虫场景下,我们发出一个请求之后,需要等待一定的时间才能得到响应,但其实在这个等待过程中,程序可以干许多其他的事情,等到响应得到之后才切换回来继续处理,这样可以充分利用 CPU 和其他资源,这就是协程的优势。

2. asyncio + aiohttp 异步爬虫

爬虫基本思路:

  • 确定目标url
  • 发送请求 获取响应
  • 解析响应 提取数据
  • 保存数据

查看网页源代码,可以找到我们想要提取的数据

检查分析网页:

可以发现一页里的每条房源的各种信息都在li标签下

第1页:https://cd.lianjia.com/ershoufang/
第2页:https://cd.lianjia.com/ershoufang/pg2/
第3页:https://cd.lianjia.com/ershoufang/pg3/
第100页:https://cd.lianjia.com/ershoufang/pg100/
分析易得翻页的规律,构造请求url列表。

异步爬虫代码如下:

import asyncio
import aiohttp
from lxml import etree
import logging
import datetime
import openpyxlwb = openpyxl.Workbook()
sheet = wb.active
sheet.append(['房源', '房子信息', '所在区域', '单价', '关注人数和发布时间', '标签'])
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
start = datetime.datetime.now()class Spider(object):def __init__(self):self.semaphore = asyncio.Semaphore(6)  # 信号量,控制协程数,防止爬的过快被反爬self.header = {"Host": "cd.lianjia.com","Referer": "https://cd.lianjia.com/ershoufang/","Cookie": "lianjia_uuid=db0b1b8b-01df-4ed1-b623-b03a9eb26794; _smt_uid=5f2eabe8.5e338ce0; UM_distinctid=173ce4f874a51-0191f33cd88e85-b7a1334-144000-173ce4f874bd6; _jzqy=1.1596894185.1596894185.1.jzqsr=baidu.-; _ga=GA1.2.7916096.1596894188; gr_user_id=6aa4d13e-c334-4a71-a611-d227d96e064a; Hm_lvt_678d9c31c57be1c528ad7f62e5123d56=1596894464; _jzqx=1.1596897192.1596897192.1.jzqsr=cd%2Elianjia%2Ecom|jzqct=/ershoufang/pg2/.-; select_city=510100; lianjia_ssid=c9a3d829-9d20-424d-ac4f-edf23ae82029; Hm_lvt_9152f8221cb6243a53c83b956842be8a=1596894222,1597055584; gr_session_id_a1a50f141657a94e=33e39c24-2a1c-4931-bea2-90c3cc70389f; CNZZDATA1253492306=874845162-1596890927-https%253A%252F%252Fwww.baidu.com%252F%7C1597054876; CNZZDATA1254525948=1417014870-1596893762-https%253A%252F%252Fwww.baidu.com%252F%7C1597050413; CNZZDATA1255633284=1403675093-1596890300-https%253A%252F%252Fwww.baidu.com%252F%7C1597052407; CNZZDATA1255604082=1057147188-1596890168-https%253A%252F%252Fwww.baidu.com%252F%7C1597052309; _qzjc=1; gr_session_id_a1a50f141657a94e_33e39c24-2a1c-4931-bea2-90c3cc70389f=true; _jzqa=1.3828792903266388500.1596894185.1596897192.1597055585.3; _jzqc=1; _jzqckmp=1; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22173ce4f8b4f317-079892aca8aaa8-b7a1334-1327104-173ce4f8b50247%22%2C%22%24device_id%22%3A%22173ce4f8b4f317-079892aca8aaa8-b7a1334-1327104-173ce4f8b50247%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D; _gid=GA1.2.865060575.1597055587; Hm_lpvt_9152f8221cb6243a53c83b956842be8a=1597055649; srcid=eyJ0Ijoie1wiZGF0YVwiOlwiOWQ4ODYyNmZhMmExM2Q0ZmUxMjk1NWE2YTRjY2JmODZiZmFjYTc2N2U1ZTc2YzM2ZDVkNmM2OGJlOWY5ZDZhOWNkN2U3YjlhZWZmZTllNGE3ZTUwYjA3NGYwNDEzMThkODg4NTBlMWZhZmRjNTIwNDBlMDQ2Mjk2NTYxOWQ1Y2VlZjE5N2FhZjUyMTZkOTcyZjg4YzNiM2U1MThmNjc5NmQ4MGUxMmU2YTM4MmI3ZmU0NmFhNTJmYmMyYWU1ZWI3MjU5YWExYTQ1YWFkZDUyZWVjMzM2NTFjYTA2M2NlM2ExMzZhNjEwYjFjYzQ0OTY5MTQwOTA4ZjQ0MjQ3N2ExMDkxNTVjODFhN2MzMzg5YWM3MzBmMTQxMjU4NzAwYzk5ODE3MTk1ZTNiMjc4NWEzN2M3MTIwMjdkYWUyODczZWJcIixcImtleV9pZFwiOlwiMVwiLFwic2lnblwiOlwiYmExZDJhNWZcIn0iLCJyIjoiaHR0cHM6Ly9jZC5saWFuamlhLmNvbS9lcnNob3VmYW5nLyIsIm9zIjoid2ViIiwidiI6IjAuMSJ9; _qzja=1.726562344.1596894309336.1596897192124.1597055583833.1597055601626.1597055649949.0.0.0.12.3; _qzjb=1.1597055583833.3.0.0.0; _qzjto=3.1.0; _jzqb=1.3.10.1597055585.1; _gat=1; _gat_past=1; _gat_global=1; _gat_new_global=1; _gat_dianpu_agent=1","User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"}async def scrape(self, url):async with self.semaphore:session = aiohttp.ClientSession(headers=self.header)response = await session.get(url)result = await response.text()await session.close()return resultasync def scrape_index(self, page):url = f'https://cd.lianjia.com/ershoufang/pg{page}/'text = await self.scrape(url)await self.parse(text)async def parse(self, text):html = etree.HTML(text)lis = html.xpath('//*[@id="content"]/div[1]/ul/li')for li in lis:house_data = li.xpath('.//div[@class="title"]/a/text()')[0]             # 房源house_info = li.xpath('.//div[@class="houseInfo"]/text()')[0]           # 房子信息address = ' '.join(li.xpath('.//div[@class="positionInfo"]/a/text()'))  # 位置信息price = li.xpath('.//div[@class="priceInfo"]/div[2]/span/text()')[0]    # 单价 元/平米attention_num = li.xpath('.//div[@class="followInfo"]/text()')[0]       # 关注人数和发布时间tag = ' '.join(li.xpath('.//div[@class="tag"]/span/text()'))            # 标签sheet.append([house_data, house_info, address, price, attention_num, tag])logging.info([house_data, house_info, address, price, attention_num, tag])def main(self):# 100页的数据scrape_index_tasks = [asyncio.ensure_future(self.scrape_index(page)) for page in range(1, 101)]loop = asyncio.get_event_loop()tasks = asyncio.gather(*scrape_index_tasks)loop.run_until_complete(tasks)if __name__ == '__main__':spider = Spider()spider.main()wb.save('house.xlsx')delta = (datetime.datetime.now() - start).total_seconds()print("用时:{:.3f}s".format(delta))

运行结果如下:

成功爬取了100页的数据,共有3000条房源信息,用时15.976s。

多线程版爬虫如下:

import requests
from lxml import etree
import openpyxl
from concurrent.futures import ThreadPoolExecutor
import datetime
import loggingheaders = {"Host": "cd.lianjia.com","Referer": "https://cd.lianjia.com/ershoufang/","Cookie": "lianjia_uuid=db0b1b8b-01df-4ed1-b623-b03a9eb26794; _smt_uid=5f2eabe8.5e338ce0; UM_distinctid=173ce4f874a51-0191f33cd88e85-b7a1334-144000-173ce4f874bd6; _jzqy=1.1596894185.1596894185.1.jzqsr=baidu.-; _ga=GA1.2.7916096.1596894188; gr_user_id=6aa4d13e-c334-4a71-a611-d227d96e064a; Hm_lvt_678d9c31c57be1c528ad7f62e5123d56=1596894464; _jzqx=1.1596897192.1596897192.1.jzqsr=cd%2Elianjia%2Ecom|jzqct=/ershoufang/pg2/.-; select_city=510100; lianjia_ssid=c9a3d829-9d20-424d-ac4f-edf23ae82029; Hm_lvt_9152f8221cb6243a53c83b956842be8a=1596894222,1597055584; gr_session_id_a1a50f141657a94e=33e39c24-2a1c-4931-bea2-90c3cc70389f; CNZZDATA1253492306=874845162-1596890927-https%253A%252F%252Fwww.baidu.com%252F%7C1597054876; CNZZDATA1254525948=1417014870-1596893762-https%253A%252F%252Fwww.baidu.com%252F%7C1597050413; CNZZDATA1255633284=1403675093-1596890300-https%253A%252F%252Fwww.baidu.com%252F%7C1597052407; CNZZDATA1255604082=1057147188-1596890168-https%253A%252F%252Fwww.baidu.com%252F%7C1597052309; _qzjc=1; gr_session_id_a1a50f141657a94e_33e39c24-2a1c-4931-bea2-90c3cc70389f=true; _jzqa=1.3828792903266388500.1596894185.1596897192.1597055585.3; _jzqc=1; _jzqckmp=1; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22173ce4f8b4f317-079892aca8aaa8-b7a1334-1327104-173ce4f8b50247%22%2C%22%24device_id%22%3A%22173ce4f8b4f317-079892aca8aaa8-b7a1334-1327104-173ce4f8b50247%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D; _gid=GA1.2.865060575.1597055587; Hm_lpvt_9152f8221cb6243a53c83b956842be8a=1597055649; srcid=eyJ0Ijoie1wiZGF0YVwiOlwiOWQ4ODYyNmZhMmExM2Q0ZmUxMjk1NWE2YTRjY2JmODZiZmFjYTc2N2U1ZTc2YzM2ZDVkNmM2OGJlOWY5ZDZhOWNkN2U3YjlhZWZmZTllNGE3ZTUwYjA3NGYwNDEzMThkODg4NTBlMWZhZmRjNTIwNDBlMDQ2Mjk2NTYxOWQ1Y2VlZjE5N2FhZjUyMTZkOTcyZjg4YzNiM2U1MThmNjc5NmQ4MGUxMmU2YTM4MmI3ZmU0NmFhNTJmYmMyYWU1ZWI3MjU5YWExYTQ1YWFkZDUyZWVjMzM2NTFjYTA2M2NlM2ExMzZhNjEwYjFjYzQ0OTY5MTQwOTA4ZjQ0MjQ3N2ExMDkxNTVjODFhN2MzMzg5YWM3MzBmMTQxMjU4NzAwYzk5ODE3MTk1ZTNiMjc4NWEzN2M3MTIwMjdkYWUyODczZWJcIixcImtleV9pZFwiOlwiMVwiLFwic2lnblwiOlwiYmExZDJhNWZcIn0iLCJyIjoiaHR0cHM6Ly9jZC5saWFuamlhLmNvbS9lcnNob3VmYW5nLyIsIm9zIjoid2ViIiwidiI6IjAuMSJ9; _qzja=1.726562344.1596894309336.1596897192124.1597055583833.1597055601626.1597055649949.0.0.0.12.3; _qzjb=1.1597055583833.3.0.0.0; _qzjto=3.1.0; _jzqb=1.3.10.1597055585.1; _gat=1; _gat_past=1; _gat_global=1; _gat_new_global=1; _gat_dianpu_agent=1","User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"}
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
wb = openpyxl.Workbook()
sheet = wb.active
sheet.append(['房源', '房子信息', '所在区域', '单价', '关注人数和发布时间', '标签'])
start = datetime.datetime.now()def get_house(page):if page == 1:url = "https://cd.lianjia.com/ershoufang/"else:url = f"https://cd.lianjia.com/ershoufang/pg{page}/"res = requests.get(url, headers=headers)html = etree.HTML(res.text)lis = html.xpath('//*[@id="content"]/div[1]/ul/li')for li in lis:house_data = li.xpath('.//div[@class="title"]/a/text()')[0]             # 房源house_info = li.xpath('.//div[@class="houseInfo"]/text()')[0]           # 房子信息address = ' '.join(li.xpath('.//div[@class="positionInfo"]/a/text()'))  # 位置信息price = li.xpath('.//div[@class="priceInfo"]/div[2]/span/text()')[0]    # 单价 元/平米attention_num = li.xpath('.//div[@class="followInfo"]/text()')[0]       # 关注人数和发布时间tag = ' '.join(li.xpath('.//div[@class="tag"]/span/text()'))            # 标签sheet.append([house_data, house_info, address, price, attention_num, tag])logging.info([house_data, house_info, address, price, attention_num, tag])if __name__ == '__main__':with ThreadPoolExecutor(max_workers=6) as executor:executor.map(get_house, [page for page in range(1, 101)])wb.save('house.xlsx')delta = (datetime.datetime.now() - start).total_seconds()print("用时:{:.3f}s".format(delta))

运行结果如下:

成功爬取了100页的数据,共有3000条房源信息,用时16.796s。

3. 其他说明

  • 从以上简单测试可以看出,将异步请求灵活运用在爬虫中,在服务器能承受高并发的前提下增加并发数量,爬取效率提升是非常可观的。
  • 爬虫代码仅用于python爬虫知识交流,勿作其他用途,违者后果自负。
  • 不建议抓取太多数据,容易对服务器造成负载,浅尝辄止即可。

你学会了。如需要资料源码或者视频教程加群:1136192749

如有侵权联系小编删除

Python爬取链家成都二手房源信息,异步爬虫实战项目!相关推荐

  1. Python爬取链家成都二手房源信息

    作者 | 旧时晚风拂晓城 编辑 | JackTian 来源 | 杰哥的IT之旅(ID:Jake_Internet) 转载请联系授权(微信ID:Hc220066) 公众号后台回复:「成都二手房数据」,获 ...

  2. Python爬取链家成都小区信息

    事先声明,本人爬虫初学者,实习时需要用到房价数据,故上阵爬虫,水平有限,若有高见,还请多多指教. 准备工具:Chrome浏览器.Python3.7.IPython notebook 爬虫流程 1.进入 ...

  3. Python爬取链家地产二手房信息

    """ 1.爬取链家地产二手房信息 要求:使用代理进行爬取:59.58.151.34:3879 步骤:1.找URL第一页:https://yichang.lianjia. ...

  4. 掌财社:python怎么爬取链家二手房的数据?爬虫实战!

    我们知道爬虫的比较常见的应用都是应用在数据分析上,爬虫作为数据分析的前驱,它负责数据的收集.今天我们以python爬取链家二手房数据为例来进行一个python爬虫实战.(内附python爬虫源代码) ...

  5. Python爬取链家北京租房信息

    刚学习了python,中途遇到很多问题,查了很多资料,最关键的就是要善于调试,div信息一定不要找错,下面就是我爬取租房信息的代码和运行结果: 链家的房租网站 两个导入的包 1.requests 用来 ...

  6. Python爬取链家北京租房信息!北京租房都租不起啊!

    一.效果图 二.代码 import re from fake_useragent import UserAgent from lxml import etree import asyncio impo ...

  7. python爬取boss直聘招聘信息_Python爬虫实战-抓取boss直聘招聘信息

    Python Python开发 Python语言 Python爬虫实战-抓取boss直聘招聘信息 实战内容:爬取boss直聘的岗位信息,存储在数据库,最后通过可视化展示出来 PS注意:很多人学Pyth ...

  8. python爬房源信息_用python爬取链家网的二手房信息

    题外话:这几天用python做题,算是有头有尾地完成了.这两天会抽空把我的思路和方法,还有代码贴出来,供python的初学者参考.我python的实战经历不多,所以代码也是简单易懂的那种.当然过程中还 ...

  9. python关于二手房的课程论文_基于python爬取链家二手房信息代码示例

    基本环境配置 python 3.6 pycharm requests parsel time 相关模块pip安装即可 确定目标网页数据 哦豁,这个价格..................看到都觉得脑阔 ...

最新文章

  1. java list_Java集合-List
  2. 【深度学习】深入浅出transformer内部结构
  3. TK:绘制BoundaryEdges边界边用法实战
  4. mysql重置增量_摆脱困境:在每种测试方法之前重置自动增量列
  5. 域名解析服务之DNS查询类型
  6. 读书笔记:Information Architecture for the World Wide Web, 3rd Edition 北极熊 第一部分 1-3...
  7. 安装、部署DPM 2012 R2服务器
  8. 小白设计模式:访问者模式
  9. Vision GUI programming products
  10. python django查询12306火车票
  11. Struts2——一个用来开发 MVC 应用程序的框架
  12. cefsharp 多标签_14 无序列表标签
  13. Vijos 1048 送给圣诞夜的贺卡(dfs)
  14. 第三届传智杯初赛A组G题 - 森林
  15. oracle数据投毒,Oracle Database Server ‘TNS Listener’远程数据投毒漏洞(CVE-2012-1675)的解决方案...
  16. EndnoteX9简介及基本教程使用说明
  17. 微信小程序之植物识别demo(百度开发接口)
  18. Java中多态的粗浅见解
  19. DELL 6248交换机常用配置示例
  20. 虚拟服务器 vmotion,vSphere vMotion能够同时迁移多少台虚拟机?

热门文章

  1. mysql qps 简书_什么是qps,如何看qps
  2. 水库大坝GNSS位移自动监测系统方案
  3. html:display属性
  4. QtCreator画UML
  5. JSP毕设分享 科研信息管理系统
  6. 微信公共平台开发(1)
  7. 虹科鹰眼系统将为职业棒球大联盟赋予全新意义
  8. Axure学习——页面跳转
  9. 一天测血压的最佳时间_一天中哪个时间测血压更准一点?牢记降压小技巧,血压逐步降...
  10. python list每个重复元素保留一次,python 列表(list)去除重复的元素总结