爬虫

本文详细介绍了Python爬虫的基本流程,包括使用requests或aiohttp等库抓取页面,通过正则表达式、BeautifulSoup4和XPath解析页面,以及将数据保存到Excel、CSV和数据库。还探讨了并发爬取的策略,如多线程、线程池、多进程和异步编程,以提高爬取效率。
摘要由CSDN通过智能技术生成

爬虫

抓取页面

requests / aiohttp / httpx (抓取页面较为简单,所以就不细讲,只列出方法,不会可自行搜索学习,简单易上手)

解析页面

正则表达式 —>re

首先需要导入re和requests模块

import re
import requests

使用requests.get(‘网址’) ——向网站发送get请求

resp = requests.get(
    url='https://www.sohu.com',
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
    }
)

注意(如果无法请求成功可添加User-Agent和cookie以增大请求数据成功的概率)

cookie可在网页中鼠标右键检查选择network,然后刷新网页之后点击刷新项查看headers,就可以获取cookie值

请求成功之后就可使用正则表达式进行匹配标签

# 使用正则表达式捕获组从页面代码中提取电影名称
patten = re.compile(r'\<span class="title"\>(.*?)\<\/span\>')
print(patten.findall(resp.text))

注意:\为取消符号特殊意义,(.*?)为抓取目标

抓取成功之后保存到文件夹或者数据库即可

css选择器 —>beautifulsoup4

想要使用css选择器首先得安装第三方库

在pycharm的terminal中输入pip install beautifulsoup4回车即可,显示安装成功后就可使用该第三方库

导入bs4模块

import bs4

向网站发送请求一般选取requests,参考上面即可

请求成功之后,去找到网页的代码(网站中鼠标右键检查),根据代码的标签寻找自己想要爬取内容的标签

soup = bs4.BeautifulSoup(resp.text, 'html.parser')
spans = soup.select('ul.li>div5>a')

这里写的(‘ul.li>div5>a’)意思是ul标签下的li子标签,li标签下的第五个div下的a标签

抓取成功保存即可

xpath —>从XML文件中获取元素的查询语法 —> lxml

使用xpath想要安装第三方库lxml

terminal终端输入pip install lxml,显示安装成功后就可使用该第三方库

导入lxml

from lxml import etree

使用requests向网站发送请求,成功后

去网站找到html代码,选中自己要获取的内容,鼠标右键,找到copy,找到copy xpath点击

root = etree.HTML(resp.text)
spans = root.xpath('//*[@id="content"]/div/div[1]/ol/li/div/div[2]/div[1]/a/span[1]')

注意:粘贴的xpth格式只有当前选中的一行数据,可根据自己需要的数据对代码进行修改,即可拿到想要的代码

例如去掉div[2]中的[2]

拿到数据下载保存即可

保存数据(数据持久化)

上面讲了如何爬取数据,这里将会告诉大家如何保存数据

Execl

该库是保存到表格中

安装第三方库 pip install xlwt openpyxl

导入模块xlwt

import xlwt

下面给到家参考一份我写的完整的保存数据到Excel中的代码

def main():
    # 创建工作簿
    wb = xlwt.Workbook()
    # 创建工作表
    sheet = wb.add_sheet('Top250')
    col_names = ('排名', '名称', '评分', '类型', '制片国家', '语言', '时长')
    for index, name in enumerate(col_names):
        sheet.write(0, index, name)
        rank = 0
    for page in range(10):
        resp = requests.get(
            url=f'https://movie.douban.com/top250?start={page * 25}',
            headers={
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
            }
        )
        soup = bs4.BeautifulSoup(resp.text, 'html.parser')
        info_divs = soup.select('div.info')
        for info_div in info_divs:
            rank += 1
            anchor = info_div.select_one('div.hd>a')
            detail_url = anchor.attrs['href']
            title = anchor.select_one('span.title').text
            score = info_div.select_one('div.bd>div.star>span.rating_num').text
            movie_details = [rank, title, score]
            movie_details += fetch_movie_detail(detail_url)
            for index, item in enumerate(movie_details):
                sheet.write(rank, index, item)
        wb.save('豆瓣电影.xls')

    print('程序结束')
    
    
if __name__ == '__main__':
    main()

CSV —>reader / writer(file)

CSV操作我给大家参考一份下载图片的代码,由于好理解,我就不详细给大家解释了,大家根据代码参考就可

resp = requests.get('https://bkimg.cdn.bcebos.com/pic/562c11dfa9ec8a1363271293564a868fa0ec08fa6a24?x-bce-process=image/watermark,image_d2F0ZXIvYmFpa2UxMTY=,g_7,xp_5,yp_5')
with open('sanji.png', 'wb') as file:
    file.write(resp.content)

也可将数据保存到数据库当中,这种方法一般企业使用更多,队友新手党来说,学会上面两种方法即可

数据库(Database)

关系型数据库(SQL)
库(NoSQL —> NewSQL)

并发爬取

由于爬取方式是一个一个下载,可能速度会相对较慢,我们就可以使用多线程或者多进程爬取,也可使用线程池或者进程池

多线程

多线程是由一个进程中的多个线程组成,多个线程可以同时进行文件的下载,适用于下载文件之间没有先后顺序的下载

多线程之间通信比较简单,因为线程可以共享进程的内容

使用多线程需要导入模块Thread

from threading import Thread

这里我用代码向大家演示多线程的使用方法

def record_time(func):

    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f'{func.__name__}执行时间:{end - start:.3f}秒')
        return result

    return wrapper


@record_time
def download(filename):
    print(f'开始下载{filename}')
    time.sleep(random.randint(5, 10))
    print(f'{filename}下载完成')


@record_time
def upload(filename):
    print(f'开始上传{filename}')
    time.sleep(random.randint(5, 10))
    print(f'{filename}上传完成')


# 如果程序里有好时间的任务,可能会阻塞别的任务,就用线程来执行,如果有因果关系就必须等着,按顺序执行,如果没有因果关系,就可以用线程
@record_time
def main():
    t1 = Thread(target=download, args=('Python从入门到住院.pdf', ))
    t1.start()
    t2 = Thread(target=download, args=('MySQL从删库到跑路.avi', ))
    t2.start()
    t3 = Thread(target=upload, args=('北京有点热.avi', ))
    t3.start()
    t1.join()
    t2.join()
    t3.join()


if __name__ == '__main__':
    main()

注意:args后面为元组,所以需要在最后打逗号

这里我使用了一个装饰器,用来装饰下面三个函数

线程池

使用线程池需要导入模块ThreadPoolExecutor

from concurrent.futures.thread import ThreadPoolExecutor

使用方法我之间用代码向大家演示

ef download_picture(picture_url):
    resp = requests.get(picture_url)
    if resp.status_code == 200:
        filename = picture_url[picture_url.rfind('/') + 1:]
        with open(f'images/{filename}', 'wb') as file:
            file.write(resp.content)
            
            
with ThreadPoolExecutor(max_workers=16) as pool:
    for num in range(1, 11):
        resp = requests.get('https://image.so.com/zjl?ch=beauty&t1=600&sn=30')
        data_dict = resp.json()
        for beauty_dict in data_dict['list']:
            picture_url = beauty_dict['qhimg_url']
            pool.submit(download_picture, picture_url)

多线程和多进程

使用方法和多线程,线程池差不多

将Tread替换为Process,ThreadPoolExecutor替换为ProcessPoolExecutor即可

异步编程

异步不需要排队,没有顺序,不会阻塞,也不会等待

需要模块aiohttp和asyncio

import aiohttp
import asyncio

直接代码展示

U_A = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'

urls = [
    'https://www.bilibili.com/',
    'https://www.baidu.com/',
    'https://www.sohu.com/',
    'https://www.taobao.com/',
    'https://www.jd.com/',
    'https://www.qidian.com/',
    'https://www.huya.com/',
    'https://www.douyu.com/'
]

title_pattern = re.compile(r'\<title\>(?P<foo>.*?)\<\/title\>')


async def main(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url, headers={'User-Agent': U_A}) as resp:
            page_code = await resp.text()
            match = title_pattern.search(page_code)
            if match:
                print(match.group('foo'))


cos_list = [main(url) for url in urls]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(cos_list))
loop.close()
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值