Python爬虫入门(结合网站代码演示)

原理

第一步发送请求

与浏览器请求访问服务器地址一样,python程序向服务器发送访问请求,服务器返回数据。

在python中我们可以使用

第二步解析网页内容

浏览器在接收到服务器返回的数据后,会自行解析内容最后呈现出我们所看到的界面。但是在程序中我们收到的内容是一大串数据,我们需要分析这些数据去拿到我们想要的内容。

第三步储存和分析数据

详细过程

我们以汽车之家二手车内容为例(我随便找的网站)

发送请求

可以使用python中的requests库,来构建get请求

import requests

# 定义headers参数,修改 User-Agent来模拟浏览器的请求访问
# 如果不写user-agent,服务器会知道这个get请求是来自于程序发出的而不是浏览器,对于一些不希望被爬取的网站可能会拒绝访问
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"}

# 传入headers参数,修改指定信息
response = requests.get('https://www.che168.com/china/20_30/a0_0msdgscncgpi1ltocsp1exx0/?pvareaid=102179#currengpostion', headers=headers)

if response.ok:
    # 使用response.text查看请求结果的内容
    print("请求成功")
    # print(response.text)
else:
    print("响应失败")

输出结果如下:

可以看到,我们请求响应得到的结果是一个htm文件格式的内容,这是对应网页的源码,就与我们在该网页查看详细源码的结果一样

user-agent的查询方法:进入该网站的详细页面,点击网络

解析内容

根据个人需求,我们拟定的获取目标如下:即一辆车的售价、行使公里数、上牌日期、出售地、车名

可以使用python中的BeautifulSoup库,来解析html文件,解析后的解构为树状结构,方便程序查询想要的内容,如下图:

通过在网页源码端口的详细查询,我们得知了汽车名字的信息如下:h4标签,class类别是'card-name'。

所以我们可以使用BeautifulSoup来解析和查找对应信息,代码如下:

import requests
from bs4 import BeautifulSoup

# 定义headers参数,修改 User-Agent来模拟浏览器的请求访问
# 如果不写user-agent,服务器会知道这个get请求是来自于程序发出的而不是浏览器,对于一些不希望被爬取的网站可能会拒绝访问
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"}

# 传入headers参数,修改指定信息
response = requests.get('https://www.che168.com/china/20_30/a0_0msdgscncgpi1ltocsp1exx0/?pvareaid=102179#currengpostion', headers=headers)

if response.ok:
    print("请求成功")

    # 将得到的HTML文本转换成BeautifulSoup对象
    # 因为BeautifulSoup不光可以解析HTML文件,使用需要指定解析器为HTML解析器
    soup = BeautifulSoup(response.text, 'html.parser')

    # 查找标签为h4,class_='card-name'的元素,返回一个列表
    car_name = soup.findAll('h4', class_='card-name')

    for i in car_name:

        # 因为返回的列表是标签类型,需要取出文本所以加上.string
        print(i.string)

else:
    print("响应失败")

运行结果:

辆车的售价、行使公里数、上牌日期、出售地、车名的整个解析:

由于一辆车的所有信息都放在一个<li>标签下,为了保证信息一一对应,我们放弃之前查询全部<h4>标签的做法,转而先查询所有<li>标签,然后再查询该<li>标签下的汽车名字、价格、信息等,这样就可以做到信息的对应。

对应代码如下:

# 汽车之家二手车信息爬取
import requests
from bs4 import BeautifulSoup

# 定义headers参数,修改 User-Agent来模拟浏览器的请求访问
# 如果不写user-agent,服务器会知道这个get请求是来自于程序发出的而不是浏览器,对于一些不希望被爬取的网站可能会拒绝访问
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"}

# 传入headers参数,修改指定信息
response = requests.get('https://www.che168.com/china/20_30/a0_0msdgscncgpi1ltocsp1exx0/?pvareaid=102179#currengpostion', headers=headers)

if response.ok:
    print("请求成功")

    # 创建列表储存数据
    all_data = []

    # 将得到的HTML文本转换成BeautifulSoup对象
    # 因为BeautifulSoup不光可以解析HTML文件,使用需要指定解析器为HTML解析器
    soup = BeautifulSoup(response.text, 'html.parser')

    # 找到所有li标签
    all_tag_li = soup.find_all('li', class_='cards-li list-photo-li')

    # 在每个li标签中找到想要的信息
    for tag_li in all_tag_li:
        try:
            # 价格
            price = tag_li.find('span', class_='pirce').find('em').text

            # 名字
            name = tag_li.find('h4', class_='card-name').text

            # 信息
            info = tag_li.find('p', class_='cards-unit').text

            # 加入到列表中
            all_data.append([price, name, info])

        except AttributeError:
            # 对于个别li标签不完整的,忽略并继续下一个
            continue

    for data in all_data:
        print(data)

else:
    print("响应失败")

运行结果:

结果储存

根据需求选择储存方式,这里我选项保存到本地csv文件中。代码如下:

# 汽车之家二手车信息爬取
import requests
from bs4 import BeautifulSoup
import csv

# 定义headers参数,修改 User-Agent来模拟浏览器的请求访问
# 如果不写user-agent,服务器会知道这个get请求是来自于程序发出的而不是浏览器,对于一些不希望被爬取的网站可能会拒绝访问
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"}

# 传入headers参数,修改指定信息
response = requests.get('https://www.che168.com/china/20_30/a0_0msdgscncgpi1ltocsp1exx0/?pvareaid=102179#currengpostion', headers=headers)

if response.ok:
    print("请求成功")

    # 创建列表储存数据
    all_data = []

    # 将得到的HTML文本转换成BeautifulSoup对象
    # 因为BeautifulSoup不光可以解析HTML文件,使用需要指定解析器为HTML解析器
    soup = BeautifulSoup(response.text, 'html.parser')

    # 找到所有li标签
    all_tag_li = soup.find_all('li', class_='cards-li list-photo-li')

    # 在每个li标签中找到想要的信息
    for tag_li in all_tag_li:
        try:
            # 价格
            price = tag_li.find('span', class_='pirce').find('em').text
            # 名字
            name = tag_li.find('h4', class_='card-name').text
            # 信息
            info = tag_li.find('p', class_='cards-unit').text
            # 加入到列表中
            all_data.append([price, name, info])
        except AttributeError:
            # 对于个别li标签不完整的,忽略并继续下一个
            continue

    # 定义CSV文件的路径为当前python文件所在路径目录下,名称为car_data.csv
    csv_file_path = './car_data.csv'

    with open(csv_file_path, 'w', newline='', encoding='utf-8') as csv_file:
        # 创建CSV写入器
        csv_writer = csv.writer(csv_file)
        # 写入CSV文件的表头
        csv_writer.writerow(['价格', '名称', '信息'])
        # 写入CSV文件的每一行数据
        csv_writer.writerows(all_data)

    print(f"数据已保存到 {csv_file_path}")


else:
    print("响应失败")

运行结果:

优化程序

1.上述代码只能爬取一页的内容,我们需要把整个100页内的所有汽车信息爬取下来。

2.由于<li>标签内的汽车信息是分布在一个<p>标签内的,导致爬取到的汽车公里数、上牌时间、出售地点没有得到分开,我们需要分别存储这些信息。

最终代码如下:

# 汽车之家二手车信息爬取
import os
import requests
from bs4 import BeautifulSoup
import csv


def download(page):
    # 定义headers参数,修改 User-Agent来模拟浏览器的请求访问
    # 如果不写user-agent,服务器会知道这个get请求是来自于程序发出的而不是浏览器,对于一些不希望被爬取的网站可能会拒绝访问
    headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"}

    # 传入headers参数,修改指定信息
    response = requests.get(f'https://www.che168.com/china/20_30/a0_0msdgscncgpi1ltocsp{page}exx0/?pvareaid=102179#currengpostion',headers=headers)

    if response.ok:
        # 创建列表储存数据
        all_data = []

        # 将得到的HTML文本转换成BeautifulSoup对象
        # 因为BeautifulSoup不光可以解析HTML文件,使用需要指定解析器为HTML解析器
        soup = BeautifulSoup(response.text, 'html.parser')

        # 找到所有li标签
        all_tag_li = soup.find_all('li', class_='cards-li list-photo-li')

        # 在每个li标签中找到想要的信息
        for tag_li in all_tag_li:
            try:
                # 价格
                price = tag_li.find('span', class_='pirce').find('em').text
                # 名字
                name = tag_li.find('h4', class_='card-name').text
                # 信息
                info = tag_li.find('p', class_='cards-unit').text
                # 切割信息
                info_list = info.split('/')
                # 里程
                mileage = info_list[0]
                # 上牌日期
                date = info_list[1]
                # 出售地点
                location = info_list[2]
                # 加入到列表中
                all_data.append([price, name, mileage, date, location])
            except AttributeError:
                # 对于个别li标签不完整的,忽略并继续下一个
                continue

        # 定义CSV文件的路径为当前python文件所在路径目录下,名称为car_data.csv
        csv_file_path = './car_data.csv'

        # 检查CSV文件是否存在
        if os.path.exists(csv_file_path):
            # 如果CSV文件存在,则追加写入
            with open(csv_file_path, 'a', newline='', encoding='utf-8') as csv_file:
                # 创建CSV写入器
                csv_writer = csv.writer(csv_file)
                # 写入CSV文件的每一行数据
                csv_writer.writerows(all_data)
        else:
            # 如果CSV文件不存在,则创建并写入
            with open(csv_file_path, 'w', newline='', encoding='utf-8') as csv_file:
                # 创建CSV写入器
                csv_writer = csv.writer(csv_file)
                # 写入CSV文件的表头
                csv_writer.writerow(['价格', '名称', '里程', '上牌日期', '出售地点'])
                # 写入CSV文件的每一行数据
                csv_writer.writerows(all_data)

        print(f"网页{page}爬取成功")

    else:
        print("响应失败")


if __name__ == "__main__":
    # 取100页数据
    for i in range(1, 101):
        download(i)
    print("所有网页取完成")

运行结果:

csv文件展示:

存在的问题

最后爬取到的数据只有217条,显然是远远少于实际数据的。问题出在了内容解析的时候,因为每个<li>标签不能保证都是完整的按照我们的格式来的,例如有的<li>标签缺少'span', class_='pirce'、有的<li>标签缺少'h4', class_='card-name',所以在爬取不完整标签的时候会报错AttributeError,这里我使用了异常捕获跳过了报错,同时也跳过了爬取这条不完整的数据。

后续解决了我会更新代码的。

更新:

因为在<li>标签中的class类,有的是cards-li list-photo-li cxc-card,有的是cards-li list-photo-li,所以在爬取的时候我们的代码只爬取了类别为cards-li list-photo-li的数据。

解决办法很简单,我们直接搜索指定目录下的所有<li>标签即可。

由于之前的代码headers只有user-agent,连续爬取几次后就会被网站拒绝访问,所以在headers中多添加了几个参数,让我们的爬虫程序看起来更像浏览器的访问操作。同时加入系统沉睡,限制程序每一秒只访问一个页面,减少被拒绝访问的风险。

参数的获取方法与user-agent相同

最终源码

# 汽车之家二手车信息爬取
import os
import time
import requests
from bs4 import BeautifulSoup
import csv


def download(page):
    # 定义headers参数,修改 User-Agent来模拟浏览器的请求访问
    # 如果不写user-agent,服务器会知道这个get请求是来自于程序发出的而不是浏览器,对于一些不希望被爬取的网站可能会拒绝访问
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'Accept-Encoding': 'gzip, deflate, br, zstd',
        'Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
        'Cache-Control': 'max-age=0',
        'priority': 'u=0, i',
        'upgrade-insecure-requests': '1',
        'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0",
        'Cookie': 'fvlid=1722413416137LVe9FhE7rzhg; sessionid=f4912b41-3403-445e-b9d4-4fc459234c54; sessionip=10.132.4.114; area=0; Hm_lvt_d381ec2f88158113b9b76f14c497ed48=1722413417; HMACCOUNT=055AE983BAABD8CA; che_sessionid=41B341E6-588E-4350-BC8B-0271539DE377%7C%7C2024-07-31+16%3A10%3A17.436%7C%7Cwww.autohome.com.cn; UsedCarBrowseHistory=0%3A51459576; carDownPrice=1; userarea=0; listuserarea=0; sessionvisit=c00aac7b-cd18-4f3d-9495-566e1ada5783; sessionvisitInfo=f4912b41-3403-445e-b9d4-4fc459234c54||0; che_sessionvid=5B005A7D-BFFD-46DD-8FF7-52B4D66F5ED6; ahpvno=34; Hm_lpvt_d381ec2f88158113b9b76f14c497ed48=1722431981; showNum=34; ahuuid=EEBCCA8E-4EA4-4FF4-BD14-05E154C3AFEF; v_no=34; visit_info_ad=41B341E6-588E-4350-BC8B-0271539DE377||5B005A7D-BFFD-46DD-8FF7-52B4D66F5ED6||-1||-1||34; che_ref=www.autohome.com.cn%7C0%7C100444%7C0%7C2024-07-31+21%3A19%3A42.067%7C2024-07-31+16%3A10%3A17.436; sessionuid=f4912b41-3403-445e-b9d4-4fc459234c54'
    }

    # 传入headers参数,修改指定信息
    response = requests.get(f'https://www.che168.com/china/20_30/a0_0msdgscncgpi1ltocsp{page}exx0/?pvareaid=102179#currengpostion',headers=headers)

    if response.ok:
        # 创建列表储存数据
        all_data = []

        # 将得到的HTML文本转换成BeautifulSoup对象
        # 因为BeautifulSoup不光可以解析HTML文件,使用需要指定解析器为HTML解析器
        soup = BeautifulSoup(response.text, 'html.parser')

        # 找到所有li标签
        all_tag_li = soup.find('div', class_='content fn-clear card-wrap') \
            .find('div', class_='tp-cards-tofu fn-clear') \
            .find('ul', class_='viewlist_ul').find_all('li')

        # 在每个li标签中找到想要的信息
        for tag_li in all_tag_li:
            try:
                # 价格
                price = tag_li.find('span', class_='pirce').find('em').text
                # 名字
                name = tag_li.find('h4', class_='card-name').text
                # 信息
                info = tag_li.find('p', class_='cards-unit').text
                # 切割信息
                info_list = info.split('/')
                # 里程
                mileage = info_list[0]
                # 上牌日期
                date = info_list[1]
                # 出售地点
                location = info_list[2]
                # 加入到列表中
                all_data.append([price, name, mileage, date, location])
            except AttributeError:
                # 对于个别li标签不完整的,忽略并继续下一个
                continue

        # 定义CSV文件的路径为当前python文件所在路径目录下,名称为car_data.csv
        csv_file_path = './car_data.csv'

        # 检查CSV文件是否存在
        if os.path.exists(csv_file_path):
            # 如果CSV文件存在,则追加写入
            with open(csv_file_path, 'a', newline='', encoding='utf-8') as csv_file:
                # 创建CSV写入器
                csv_writer = csv.writer(csv_file)
                # 写入CSV文件的每一行数据
                csv_writer.writerows(all_data)
        else:
            # 如果CSV文件不存在,则创建并写入
            with open(csv_file_path, 'w', newline='', encoding='utf-8') as csv_file:
                # 创建CSV写入器
                csv_writer = csv.writer(csv_file)
                # 写入CSV文件的表头
                csv_writer.writerow(['价格', '名称', '里程', '上牌日期', '出售地点'])
                # 写入CSV文件的每一行数据
                csv_writer.writerows(all_data)

        print(f"网页{page}爬取成功,找到{len(all_data)}条数据")

    else:
        print("响应失败")


if __name__ == "__main__":
    # 取100页数据
    for i in range(1, 101):
        try:
            download(i)
        except AttributeError:
            print(f"网页{i}取失败")
        time.sleep(1)  # 沉睡1秒,避免被网站拒绝
    print("所有网页取完成")

结果如下:

CSV结果如下:

最后爬取到了八千多条数据

相关推荐
_.Switch21 分钟前
Python 自动化运维持续优化与性能调优
运维·开发语言·python·缓存·自动化·运维开发
徐*红22 分钟前
java 线程池
java·开发语言
尚学教辅学习资料22 分钟前
基于SSM的养老院管理系统+LW示例参考
java·开发语言·java毕设·养老院
1 9 J24 分钟前
Java 上机实践4(类与对象)
java·开发语言·算法
Code apprenticeship25 分钟前
Java面试题(2)
java·开发语言
J不A秃V头A27 分钟前
Python爬虫:获取国家货币编码、货币名称
开发语言·爬虫·python
阿斯卡码2 小时前
jupyter添加、删除、查看内核
ide·python·jupyter
SRY122404193 小时前
javaSE面试题
java·开发语言·面试
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言
ZIM学编程3 小时前
Java基础Day-Sixteen
java·开发语言·windows