Python爬虫小白入门教程,使用BeautifulSoup爬取网站信息

Python爬虫入门教程,使用BeautifulSoup爬取网站信息

前言

笔者也是爬虫小白,平时主要是做Java开发的,只有一些python基础,最近两天想帮朋友写一个简单的爬虫程序,写这篇文章记录一下自己的学习过程。相信对于之前没有爬虫经验的小白来说,有一定的参考价值。

1.准备阶段

再进行程序编写前,我们首先需要准备python环境,还有以下几个版本包

from bs4 import BeautifulSoup  # 网页解析,获取数据
import xlwt  # 进行excel操作
import requests # 发送请求
import json
import time # 用来暂停的(限制访问频率)

其中json和time是python自带的,其余三个包需要自己安装,可以通过在控制台输入以下命令进行安装(-i 后面的命令表示使用国内镜像安装,使用默认安装可能会因为网络问题导致安装失败)

pip install Beautifulsoup4 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple

2.实现思路

爬虫其实就是首先需要确定自己想爬的内容是在哪个页面中,然后根据URL去获得这个页面的HTML,我们需要的数据一般都在html的标签中,通过解析HTML页面拿到自己需要的内容就可以了。

本次我想爬取的内容是在数据列表的详情信息页中
在这里插入图片描述

想要知道详情页面的URL的话,我们首先在浏览器(我用的是edge,谷歌也是类似的)中,按F12(有的系统可能需要Fn+F12)进入开发者页面,然后点击网络,先点击左上角清空一下当前日志,方便一会点击查看详情后找到我们的URL请求。

在这里插入图片描述

这时候点击查看按钮,我们可以看到本次请求的请求信息和响应信息

在这里插入图片描述

在多点击几个详情页面后,我们会发现它们的请求URL只有id=xxxxx是有区别的,那我们只需要拿到这些id,写个for循环就可以访问所有的详情页面了。

这时候我们在返回列表页面,通过查看请求列表数据的请求体和响应报文,可以发现列表每条数据的信息都在响应中返回了。

在这里插入图片描述

它的报文结构大概是这样,其中的id就是我们需要的。

{
    "code": 0,
    "count": 584,
    "data":[
                {
            "id": 994171,
            "time": "2023-12-31 12:30:32",
            "first_time": "2023-12-31 12:40:41",
            "dial_time": null,
            "next_time": "",
            "dial_duration": null,
            "numberin": "DRSSMZ2312310023",
            "big_case": 1,
            "grade": 4,
            "type": 1,
            "sinvalid": 1,
            "status": 1,
            "classify": 3,
            "name_y": "某",
            "follow_status": "待跟进",
            "dial_type": null,
            "types": "人损",
            "new_time": "2023-12-31 12:40:41",
            "follow_content": "正在跟进",
            "contract_num": 0
        },
        {
            "id": 992924,
            "time": "2023-12-29 14:52:20",
            "first_time": "2023-12-29 14:52:39",
            "dial_time": null,
            "next_time": "",
            "dial_duration": null,
            "numberin": "DHYBDAA2312290034",
            "big_case": 1,
            "grade": 4,
            "type": 1,
            "sinvalid": 1,
            "status": 1,
            "classify": 1,
            "name_y": "杨女士",
            "follow_status": "纯咨询",
            "dial_type": null,
            "types": "合同",
            "new_time": "2023-12-29 15:05:33",
            "follow_content": ",
            "contract_num": 0
        }
    ]
}

我是将浏览器中的这段json报文复制粘贴到本地,放到一个文件中,然后使用python读取文件,把id都存到一个list中,,在使用request发送请求的时候,只需要在URL中每次拼接上id就行了。

# 解析json数据
def getIdListData():
    with open("data/predata.json", 'r') as f:
        data = json.load(f)
    data_list = data.get('data')
    idList = []
    for i in data_list:
        idList.append(i.get('id'))
    return idList

3.实现过程

我们在使用python写爬虫的时候,一般需要三个东西:URL、请求方式、表头信息(Cookie、User-Agent等),这些都可以在浏览器中拿到

在这里插入图片描述

在这里插入图片描述

拿到这些之后,我们去详情页面,找到我们需要的数据是在哪个标签中,比如我们想要真实姓名这个信息。我们只需要点击开发者页面后,选择左上角的选择按钮,再点到需要的数据中,就可以看到它在HTML的哪个标签中了。

在这里插入图片描述

接着我们在这个标签上点击右键,选择复制selector,这样可以直接复制到它的层级结构

在这里插入图片描述

获取电话号码的代码如下

def getData(header,url):
    header = header
    url = url
    res = requests.get(url, headers=header)
    # 整个页面的HTML
    html_doc = res.text
    # soup是<class 'bs4.BeautifulSoup'>类型 可以使用.find()、findAll()等方法
    soup = BeautifulSoup(html_doc, 'html.parser')
    # 拿到电话号码的标签 参数就是selector中的内容
    phone_tag = soup.select(
        'body > div.cr-detail-box > div.cr-card-box.flex_one > div.cr-card-body > form > div.cr-play-form-list > div:nth-child(3) > div > div.value-box > input')
    # 因为值在标签的value中
    phone = phone_tag[0]['value']
 

获取所有信息的完整代码如下,因为我这次需要一个跟进记录的信息,这个信息每条数据里它的数量都不一样,因此我需要拿到它的父标签,然后通过循环去遍历拿到里面的信息。

# 爬取数据
def getData(header,url):
    header = header
    url = url
    res = requests.get(url, headers=header)
    html_doc = res.text
    # soup是<class 'bs4.BeautifulSoup'>类型 可以使用.find()、findAll()等方法
    soup = BeautifulSoup(html_doc, 'html.parser')
    # print(type(soup))
    phone_tag = soup.select(
        'body > div.cr-detail-box > div.cr-card-box.flex_one > div.cr-card-body > form > div.cr-play-form-list > div:nth-child(3) > div > div.value-box > input')
    # <class 'bs4.element.ResultSet'>
    # name_tag[0] 是<class 'bs4.BeautifulSoup'>类型
    name_tag = soup.select(
        'body > div.cr-detail-box > div.cr-card-box.flex_one > div.cr-card-body > form > div.cr-play-form-list > div:nth-child(5) > div > div.value-box > input')
    # print(type(name_tag))
    # 跟进记录外层标签
    record_tagSource = soup.select(
        '#FOLLOW_MODULE > div.cr-laymod-box > div.cr-laymod-body.nofoot.cr-timeline-wrap > div')

    children_record = record_tagSource[0]
    phone = phone_tag[0]['value']
    name = name_tag[0]['value']
    names = []
    phones = []
    # 获取存储姓名的标签集合
    names_tag = children_record.findAll(name="span", attrs={"class": "title"})
    times_tag = children_record.findAll(name="div", attrs={"class": "time-box"})
    content_tag = children_record.findAll(name="div", attrs={"class": "explain-box"})
    # 跟进记录姓名
    namesRecord = []
    # 跟进记录时间
    timesRecord = []
    # 跟进记录内容
    contentRecord = []

    # i 是这种格式 <span class="title">王卓翔</span>
    # 是bs4.element.Tag 类型,使用i.text获取标签间的内容
    # 遍历得到当前跟进记录中的所有姓名
    for i in names_tag:
        namesRecord.append(i.text)
        phones.append(phone)
        names.append(name)
    for i in times_tag:
        timesRecord.append(i.text)
    # 获取跟进记录内容
    for i in content_tag:
        # 因为从网页爬取的跟进记录中存在\n\r空格等字符,需要处理一下 只截取“xxx”中的内容
        strT = i.text
        # 获取字符串中字符首次出现的位置
        startIdx = strT.find('“')
        # 获取字符串中字符最后一次出现的位置
        endIdx = strT.rfind('”')
        strN = strT[startIdx + 1:endIdx]+""
        contentRecord.append(strN)
    return names,phones,namesRecord,timesRecord,contentRecord

将数据存到excel中的代码

# 将数据存到excel中
'''   
    :param names: 姓名列表
    :param phones: 电话列表
    :param namesRecord: 跟进人姓名列表
    :param timesRecord: 跟进时间列表
    :param contentRecord: 跟进内容列表
    :param filename: 导出文件名称
    :return: null
'''
def outPutExcel(names,phones,namesRecord,timesRecord,contentRecord,filename):

    work_book = xlwt.Workbook(encoding='UTF-8')
    worksheet = work_book.add_sheet('跟进记录')
    size = len(names)
    for i in range(1,size+1):
        worksheet.write(i,1,names[i-1])
        worksheet.write(i,2,phones[i-1])
        worksheet.write(i,3,namesRecord[i-1])
        worksheet.write(i,4,timesRecord[i-1])
        worksheet.write(i,5,contentRecord[i-1])
    work_book.save(filename)

最后是整个程序的完整代码,我把里面的cookie信息去掉了,大家拿到后可以无法直接运行出结果,主要是参考

from bs4 import BeautifulSoup  # 网页解析,获取数据
import xlwt  # 进行excel操作
import requests # 发送请求
import json
import time # 用来暂停的
# 解析json数据
def getIdListData():
    with open("data/predata.json", 'r') as f:
        data = json.load(f)
    data_list = data.get('data')
    idList = []
    for i in data_list:
        idList.append(i.get('id'))
    return idList
# 爬取数据
def getData(header,url):
    header = header
    url = url
    res = requests.get(url, headers=header)
    # 整个页面的HTML
    html_doc = res.text
    # soup是<class 'bs4.BeautifulSoup'>类型 可以使用.find()、findAll()等方法
    soup = BeautifulSoup(html_doc, 'html.parser')
    # 拿到电话号码的标签
    phone_tag = soup.select(
        'body > div.cr-detail-box > div.cr-card-box.flex_one > div.cr-card-body > form > div.cr-play-form-list > div:nth-child(3) > div > div.value-box > input')
    # <class 'bs4.element.ResultSet'>
    # name_tag[0] 是<class 'bs4.BeautifulSoup'>类型
    # 拿到姓名的标签
    name_tag = soup.select(
        'body > div.cr-detail-box > div.cr-card-box.flex_one > div.cr-card-body > form > div.cr-play-form-list > div:nth-child(5) > div > div.value-box > input')
    # print(type(name_tag))
    # 跟进记录外层标签(因为跟进记录的数量不是固定的,最内层标签需要遍历获取)
    record_tagSource = soup.select(
        '#FOLLOW_MODULE > div.cr-laymod-box > div.cr-laymod-body.nofoot.cr-timeline-wrap > div')

    children_record = record_tagSource[0]
    phone = phone_tag[0]['value']
    name = name_tag[0]['value']
    names = []
    phones = []
    # 获取存储姓名的标签集合 跟进label、class名称去获取
    names_tag = children_record.findAll(name="span", attrs={"class": "title"})
    times_tag = children_record.findAll(name="div", attrs={"class": "time-box"})
    content_tag = children_record.findAll(name="div", attrs={"class": "explain-box"})
    # 跟进记录姓名
    namesRecord = []
    # 跟进记录时间
    timesRecord = []
    # 跟进记录内容
    contentRecord = []

    # i 是这种格式 <span class="title">王卓翔</span>
    # 是bs4.element.Tag 类型,使用i.text获取标签间的内容
    # 遍历得到当前跟进记录中的所有姓名
    for i in names_tag:
        namesRecord.append(i.text)
        phones.append(phone)
        names.append(name)
    for i in times_tag:
        timesRecord.append(i.text)
    # 获取跟进记录内容
    for i in content_tag:
        # 因为从网页爬取的跟进记录中存在\n\r空格等字符,需要处理一下 只截取“xxx”中的内容
        strT = i.text
        # 获取字符串中字符首次出现的位置
        startIdx = strT.find('“')
        # 获取字符串中字符最后一次出现的位置
        endIdx = strT.rfind('”')
        strN = strT[startIdx + 1:endIdx]+""
        contentRecord.append(strN)
    return names,phones,namesRecord,timesRecord,contentRecord

# 将数据存到excel中
'''   
    :param names: 姓名列表
    :param phones: 电话列表
    :param namesRecord: 跟进人姓名列表
    :param timesRecord: 跟进时间列表
    :param contentRecord: 跟进内容列表
    :param filename: 导出文件名称
    :return: null
'''
def outPutExcel(names,phones,namesRecord,timesRecord,contentRecord,filename):

    work_book = xlwt.Workbook(encoding='UTF-8')
    worksheet = work_book.add_sheet('跟进记录')
    size = len(names)
    for i in range(1,size+1):
        worksheet.write(i,1,names[i-1])
        worksheet.write(i,2,phones[i-1])
        worksheet.write(i,3,namesRecord[i-1])
        worksheet.write(i,4,timesRecord[i-1])
        worksheet.write(i,5,contentRecord[i-1])
    work_book.save(filename)

def main():
    header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
        "Cookie": '自己的cookie',
        }
    # url = 'https://aycrm.lvzhoucrm.com/admin.php/admin/user/details.html?id=991323'
    nameList = []
    phonesList = []
    namesRecordList = []
    timesRecordList = []
    contentRecordList = []
    idList = getIdListData()
    print(len(idList))
    baseHeaderUrl = 'https://aycrm.lvzhoucrm.com/admin.php/admin/user/details.html?id='
    for idx,id in enumerate(idList):
        print('开始爬取第'+str(idx)+"条数据")
        url = baseHeaderUrl+str(id)
        names, phones, namesRecord, timesRecord, contentRecord = getData(header, url)
        # 追加每次爬取的数据
        nameList.extend(names)
        phonesList.extend(phones)
        namesRecordList.extend(namesRecord)
        timesRecordList.extend(timesRecord)
        contentRecordList.extend(contentRecord)
        # 爬取一次 休眠10秒
        time.sleep(3)
    outPutExcel(names=nameList,phones=phonesList,namesRecord=namesRecordList,timesRecord=timesRecordList,contentRecord=contentRecordList,filename='跟进记录.xls')


if __name__ == '__main__':
    main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值