数据采集第一次作业

代码链接:第一次数据采集实践作业码云链接

1、作业1

1.1、作业要求

排名 学校名称 省市 学校类型 总分
1 清华大学 北京 综合 852.5
2......

1.2、代码思路和关键代码展示

1.2.1、发送HTTP请求并考虑请求异常情况:

  • 使用requests.get方法向目标网址发送GET请求。

  • response.raise_for_status():如果请求失败(如404或500错误),将抛出异常。

  • 使用try-except结构捕获请求过程中可能出现的异常,并打印错误信息。

# 使用requests获取网页内容
try:
    response = requests.get(url)
    response.raise_for_status()  # 如果请求失败,将抛出异常
    # 使用“utf-8”编码,避免乱码
    html_content = response.content.decode('utf-8')
except requests.RequestException as e:
    print(f"请求错误: {e}")

1.2.2、解析网页内容并处理数据:

  • 使用BeautifulSoup解析获取到的HTML内容。

  • 使用find方法找到包含排名信息的表格。

  • 遍历表格的每一行(跳过标题行),提取每行的数据,包括排名、学校名称、省市、学校类型和总分。

  • 由于学校名称可能包含其他信息,代码中使用get_text方法和split函数来提取学校名称的第一部分。

 for row in table.find_all("tr")[1:]:  # 跳过标题行
            # 提取每行的数据
            cols = row.find_all("td")
            rank = cols[0].text.strip()
            # 学校名称只要前面的XX大学,学校名称
            school_name = cols[1].get_text(separator=" ", strip=True).split(" ")
            school_name = school_name[0]
            province = cols[2].text.strip() #省份
            school_type = cols[3].text.strip()  #学校类型
            total_score = cols[4].text.strip()  #总分

1.2.3、数据持久化存储:将数据写入CSV文件并打印在控制台:

  • 打开一个CSV文件,并使用csv.writer写入标题行和数据行。
  • 每提取一行数据,就将其写入CSV文件。
  • 在控制台打印提取的信息,使用格式化字符串进行对齐。
 with open('university_rankings.csv', 'w', newline='', encoding='utf-8-sig') as file:
        writer = csv.writer(file)
        # 写入标题行
        writer.writerow(['排名', '学校名称', '省市', '学校类型', '总分'])
        # 写入数据行
        writer.writerow([rank, school_name, province, school_type, total_score])
        # 打印提取的信息,使用格式化字符串进行对齐
        print(f"{rank:<5} {school_name:<15} {province:<5} {school_type:<10} {total_score:<10}")

1.3、结果展示

  • 控制台输出

  • 持久化存储

1.4、总结体会

  • 从网页上抓取的数据可能包含额外的空格、换行符或其他不需要的字符,这就需要进行数据清洗以确保数据的整洁性。通过使用函数text.strip()来删除不必要的空格。

  • 在爬取学校名称的时候,遇到了冗余信息如:学校英文名和985211等信息,发现所需要爬取的信息都位于空格前的首位,通过split进行获取第一个信息。

  • 最后将结果保存到.csv文件中,实现持久化存储。

2、作业2

2.1、作业要求

  • 用requests和re库方法设计某个商城(自已选择)商品比价定向爬虫,爬取该商城,以关键词“书包”搜索页面的数据,爬取商品名称和价格。

  • 输出信息:

序号 价格 商品名
1 65.00 xxx
2......

2.2、代码思路和关键代码展示

2.2.1、定义crawl_page函数

  • 这个函数用于爬取单个页面的商品信息。

  • 使用time.sleep添加随机等待时间,以模拟正常用户行为。

  • 构造完整的URL,并发送GET请求,如果请求失败或发生异常,则打印错误信息。。

  • 如果请求成功(状态码200),则使用正则表达式提取商品名称和价格。

  • 使用csv.writer将提取的信息写入CSV文件,并使用锁lock确保线程安全。

# 锁对象,用于在写入CSV文件时避免冲突
lock = threading.Lock()
def crawl_page(page, start_url, headers, csv_file):
    """
    爬取单个页面的商品信息并保存到CSV文件中
    """
    time.sleep(random.randint(2, 4))  # 随机等待时间,模拟正常用户行为
    url = f"{start_url}{page}"
    try:
        response = requests.get(url=url, headers=headers)
        if response.status_code == 200:
            text = response.text
            # 正则表达式模式
            pattern1 = r"alt='([^']*)'" #商品名称
            pattern2 = r"&yen;(\d+\.\d{2})" #商品价格
            # 使用正则表达式搜索
            matches1 = re.findall(pattern1, text)
            matches2 = re.findall(pattern2, text)

2.2.2、定义main函数

  • 这个函数是主程序,用于使用多线程爬取多个页面。

  • 定义请求头headers,包括用户代理和Cookie。

  • 检查CSV文件是否存在,如果不存在则创建文件并写入标题行。

  • 循环创建线程,每个线程负责爬取一个页面的商品信息。

  • 使用thread.start()启动线程,并将线程对象添加到线程列表中。

  • 使用thread.join()等待所有线程完成

def main(start_url, start_page, end_page, csv_file):
    """
    主程序,使用多线程爬取多个页面
    """
    headers = {}
    # 确保CSV文件存在
    if not os.path.exists(csv_file):
        with open(csv_file, 'w', newline='', encoding='utf-8-sig') as file:
            writer = csv.writer(file)
            writer.writerow(['序号', '商品名称', '价格'])

    threads = []
    for page in range(start_page, end_page + 1):
        thread = threading.Thread(target=crawl_page, args=(page, start_url, headers, csv_file))
        thread.start()
        threads.append(thread)
    for thread in threads:
        thread.join()

2.3、结果展示

  • 控制台输出:

  • 持久化存储:

2.4、总结体会

  • 模拟正常用户行为:通过在请求间添加随机等待时间,可以模拟正常用户的浏览行为,减少被服务器识别为爬虫的风险。

  • 用户代理和Cookie:在请求头中设置用户代理和Cookie可以模拟特定浏览器的请求,对于访问某些需要具有反爬机制的页面是必要的。

  • 多线程提高效率:通过使用threading库,程序能够同时发送多个HTTP请求,显著提高了爬取数据的效率。这对于需要爬取大量页面的情况特别有用。

  • 线程安全:在多线程环境中写入文件时,使用锁(threading.Lock)来确保线程安全,避免数据写入时的冲突。

3、作业3

3.1、作业要求

3.2、代码思路和关键代码展示

3.2.1、解析网页内容:

  • 使用BeautifulSoup解析获取到的HTML内容。

  • 使用re.compile定义一个正则表达式,用于匹配JPEG和JPG图片的URL

if response.status_code == 200:
    # 解析网页内容
    soup = BeautifulSoup(response.text, 'html.parser')
    # 创建一个目录来保存图片
    image_folder = 'fzu_images'
    if not os.path.exists(image_folder):
        os.makedirs(image_folder)
    # 正则表达式,匹配JPEG和JPG图片
    image_pattern = re.compile(r'.*\.(jpg|jpeg)$')

3.2.2、遍历并下载图片:

  • 使用soup.find_all('img')找到网页中所有的标签。

  • 对于每个标签,获取其src属性,即图片的URL。

  • 使用正则表达式检查URL是否以.jpg或.jpeg结尾,以确保只下载JPEG和JPG格式的图片。

  • 根据图片URL的前缀(如//、/),构建完整的图片URL。

  • 发送GET请求下载图片,并使用os.path.basename提取图片文件名。

  • 将图片内容写入文件,保存到之前创建的目录中。

 # 遍历网页中所有的<img>标签
    for img_tag in soup.find_all('img'):
        img_url = img_tag.get('src')
        # 使用正则表达式检查图片格式
        if img_url and image_pattern.search(img_url):
            # 尝试构建完整的图片URL
            if img_url.startswith('//'):
                full_img_url = 'https:' + img_url
            elif img_url.startswith('/'):
                full_img_url = 'https://news.fzu.edu.cn' + img_url
            else:
                full_img_url = img_url  # 已经是完整的URL
            # 获取图片内容
            try:
                img_response = requests.get(url=full_img_url,headers=headers)
                img_response.raise_for_status()  # 确保请求成功
                # 提取图片文件名
                img_filename = os.path.join(image_folder, os.path.basename(img_url))
                # 保存图片
                with open(img_filename, 'wb') as f:
                    f.write(img_response.content)
                    print(f'图片已保存:{img_filename}')
            except requests.exceptions.RequestException as e:
                print(f"无法下载图片:{full_img_url},错误:{e}")

3.3、结果展示

  • 控制台输出

  • 持久化存储

3.4、总结体会

  • 此次爬取的图片只有3张,于是特意看了一下页面原数据,发现其他大部分图片后缀为.png,不过作业要求为爬取jpg和jpeg的图片,所以就没有对代码做进一步修改。

  • 通过正则表达式匹配,可以筛选出特定格式的图片链接,实现对网页中图片的选择性下载。

  • os库提供了丰富的方法来操作文件系统,如创建目录、获取文件路径等。

posted @ 2024-10-15 20:16  oolone  阅读(10)  评论(0编辑  收藏  举报