博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python链家网高并发异步爬虫asyncio+aiohttp+aiomysql异步存入数据
阅读量:6156 次
发布时间:2019-06-21

本文共 4552 字,大约阅读时间需要 15 分钟。

python链家网二手房异步IO爬虫,使用asyncio、aiohttp和aiomysql

很多小伙伴初学python时都会学习到爬虫,刚入门时会使用requests、urllib这些同步的库进行单线程爬虫,速度是比较慢的,后学会用scrapy框架进行爬虫,速度很快,原因是scrapy是基于twisted多线程异步IO框架。

本例使用的asyncio也是一个异步IO框架,在python3.5以后加入了协程的关键字async,能够将协程和生成器区分开来,更加方便使用协程。
经过测试,平均1秒可以爬取30个详情页信息
可以使用asyncio.Semaphore来控制并发数,达到限速的效果

1579698-20190305120650251-1695379729.png

1579698-20190305120658440-746826969.png

# -*- coding: utf-8 -*-"""    :author: KK    :url: http://github.com/PythonerKK    :copyright: © 2019 KK <705555262@qq.com.com>"""import asyncioimport reimport aiohttpfrom pyquery import PyQueryimport aiomysqlfrom lxml import etreepool = ''#sem = asyncio.Semaphore(4)  用来控制并发数,不指定会全速运行stop = Falseheaders = {    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}MAX_PAGE = 10TABLE_NAME = 'data'  #数据表名city = 'zh'  #城市简写url = 'https://{}.lianjia.com/ershoufang/pg{}/'  #url地址拼接urls = []  #所有页的url列表links_detail = set()  #爬取中的详情页链接的集合crawled_links_detail = set()  #爬取完成的链接集合,方便去重async def fetch(url, session):    '''    aiohttp获取网页源码    '''    # async with sem:    try:        async with session.get(url, headers=headers, verify_ssl=False) as resp:            if resp.status in [200, 201]:                data = await resp.text()                return data    except Exception as e:        print(e)def extract_links(source):    '''    提取出详情页的链接    '''    pq = PyQuery(source)    for link in pq.items("a"):        _url = link.attr("href")        if _url and re.match('https://.*?/\d+.html', _url) and _url.find('{}.lianjia.com'.format(city)):            links_detail.add(_url)    print(links_detail)def extract_elements(source):    '''    提取出详情页里面的详情内容    '''    try:        dom = etree.HTML(source)        id = dom.xpath('//link[@rel="canonical"]/@href')[0]        title = dom.xpath('//title/text()')[0]        price = dom.xpath('//span[@class="unitPriceValue"]/text()')[0]        information = dict(re.compile('
  • (.*?)(.*?)
  • ').findall(source)) information.update(title=title, price=price, url=id) print(information) asyncio.ensure_future(save_to_database(information, pool=pool)) except Exception as e: print('解析详情页出错!') passasync def save_to_database(information, pool): ''' 使用异步IO方式保存数据到mysql中 注:如果不存在数据表,则创建对应的表 ''' COLstr = '' # 列的字段 ROWstr = '' # 行字段 ColumnStyle = ' VARCHAR(255)' for key in information.keys(): COLstr = COLstr + ' ' + key + ColumnStyle + ',' ROWstr = (ROWstr + '"%s"' + ',') % (information[key]) # 异步IO方式插入数据库 async with pool.acquire() as conn: async with conn.cursor() as cur: try: await cur.execute("SELECT * FROM %s" % (TABLE_NAME)) await cur.execute("INSERT INTO %s VALUES (%s)"%(TABLE_NAME, ROWstr[:-1])) print('插入数据成功') except aiomysql.Error as e: await cur.execute("CREATE TABLE %s (%s)" % (TABLE_NAME, COLstr[:-1])) await cur.execute("INSERT INTO %s VALUES (%s)" % (TABLE_NAME, ROWstr[:-1])) except aiomysql.Error as e: print('mysql error %d: %s' % (e.args[0], e.args[1]))async def handle_elements(link, session): ''' 获取详情页的内容并解析 ''' print('开始获取: {}'.format(link)) source = await fetch(link, session) #添加到已爬取的集合中 crawled_links_detail.add(link) extract_elements(source)async def consumer(): ''' 消耗未爬取的链接 ''' async with aiohttp.ClientSession() as session: while not stop: if len(urls) != 0: _url = urls.pop() source = await fetch(_url, session) print(_url) extract_links(source) if len(links_detail) == 0: print('目前没有待爬取的链接') await asyncio.sleep(2) continue link = links_detail.pop() if link not in crawled_links_detail: asyncio.ensure_future(handle_elements(link, session))async def main(loop): global pool pool = await aiomysql.create_pool(host='127.0.0.1', port=3306, user='root', password='xxxxxx', db='aiomysql_lianjia', loop=loop, charset='utf8', autocommit=True) for i in range(1, MAX_PAGE): urls.append(url.format(city, str(i))) print('爬取总页数:{} 任务开始...'.format(str(MAX_PAGE))) asyncio.ensure_future(consumer())if __name__ == '__main__': loop = asyncio.get_event_loop() asyncio.ensure_future(main(loop)) loop.run_forever()

    转载于:https://www.cnblogs.com/PyKK2019/p/aiohttp_spider.html

    你可能感兴趣的文章
    SQL优化技巧
    查看>>
    thead 固定,tbody 超出滚动(附带改变滚动条样式)
    查看>>
    Dijkstra算法
    查看>>
    css 动画 和 响应式布局和兼容性
    查看>>
    csrf 跨站请求伪造相关以及django的中间件
    查看>>
    MySQL数据类型--与MySQL零距离接触2-11MySQL自动编号
    查看>>
    生日小助手源码运行的步骤
    查看>>
    Configuration python CGI in XAMPP in win-7
    查看>>
    bzoj 5006(洛谷 4547) [THUWC2017]Bipartite 随机二分图——期望DP
    查看>>
    CF 888E Maximum Subsequence——折半搜索
    查看>>
    欧几里德算法(辗转相除法)
    查看>>
    面试题1-----SVM和LR的异同
    查看>>
    MFC控件的SubclassDlgItem
    查看>>
    如何避免历史回退到登录页面
    查看>>
    《图解HTTP》1~53Page Web网络基础 HTTP协议 HTTP报文内的HTTP信息
    查看>>
    unix环境高级编程-高级IO(2)
    查看>>
    树莓派是如何免疫 Meltdown 和 Spectre 漏洞的
    查看>>
    雅虎瓦片地图切片问题
    查看>>
    HTML 邮件链接,超链接发邮件
    查看>>
    HDU 5524:Subtrees
    查看>>