作业1

作业①

1.大学排名动态网页爬取实验

实验要求
用requests和BeautifulSoup库方法定向爬取给定网址(http://www.shanghairanking.cn/rankings/bcur/2020 )的数据,屏幕打印爬取的大学排名信息。

思路:

(1)查看网页,发现为静态网页,且没有其他反爬机制,可直接采用requests和soup。

(2)用F12查看网页,发现表内行标签为'tr',行内对应块均在'td'内,同时学校名称内有不必要的其他信息(英文名称等),中文名称在class='tooltip'属性内。依此编写正则表达式,最终得到清晰的排名信息。
核心代码:

点击查看代码
# 查找表格中的每一行(每行信息都在<tr>内)
rows = soup.find_all('tr')

for row in rows[1:]:  # 跳过表头
    #行内信息都在节点<td>内
    cols = row.find_all('td')
    if len(cols) >= 5:
        rank = cols[0].get_text(strip=True)

        # 获取学校名称
        name_tag =cols[1].find('div', class_='tooltip')
        name = name_tag.get_text(strip=True) if name_tag else cols[1].get_text(strip=True)

        province = cols[2].get_text(strip=True)
        category = cols[3].get_text(strip=True)
        score = cols[4].get_text(strip=True)
        print(f"{rank}\t{name}\t{province}\t{category}\t{score}")

实验结果

image

实验心得
1.这里发现翻页是用js(url不变),只用bs4和requests就做不到了,也翻不到福大了(loss)。
2.初次爬取学校名称时还有大量头衔(985,211)不够简洁,最后也是对正则表达式进行两层优化,在含学校名称的节点内在筛选出有tooltip的节点,也说明了正则表达式的重要性,写不好会匹配太多无关内容。

作业②

1.商城商品比价定向爬虫实验

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

思路

1.由于淘宝等大平台反爬做的太好了,这里选取百联网(https://search.bl.com)进行爬取
2.该网站内容是通过 JavaScript 动态加载的,如果只用requests,要找到其数据接口(JSON地址),然后用正则在接口返回的数据里提取想要的内容。用F12查看该网页真实的数据接口(https://search.bl.com/js/mainGoodList.html),查看商品名称和价格所属节点以编写正则表达式,最后用requests库模拟 POST 请求进行爬取。商品名称和价格节点如下图:

image

3.由于该网站翻页url时改变,可以通过改变url的方法对多页数据进行采集。通过查看负载得到表单数据如下:

image
后续代码可通过改变POST请求参数来改变爬取的页面(pageindex)和每页爬取数量(pagesize)

核心代码

点击查看代码
def parse_html_content(raw_content):
    html = raw_content
    names = re.findall(r'class="pro-name[^"]*".*?title="([^"]+)"', html, re.DOTALL)
    prices = re.findall(r'class="money-fl">\s*¥\s*([\d.]+)', html)

    return names, prices

点击查看代码
# --- 配置参数 ---
BASE_URL = "https://search.bl.com/js/mainGoodList.html"
SEARCH_KEYWORD = "书包"
PAGE_SIZE = 10  # 每次请求抓取的商品数量
MAX_ITEMS = 60  # 限定抓取的最大商品数量

# 存储所有抓取到的数据
all_products = []
current_page = 1  # 从第 1 页开始抓取
# --- 配置参数---

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/121.0.0.0 Safari/537.36",
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Origin": "https://search.bl.com",
    "Referer": "https://search.bl.com/k-%E4%B9%A6%E5%8C%85.html",
    "X-Requested-With": "XMLHttpRequest",
    "Cookie": "HWWAFSESID=a4491760474a07c89b; HWWAFSESTIME=1761122765955; __bl_test_id_=AECC49679A349A36126E89157AC51247; sensorsdata_is_new_user=true; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2219a0b18d44bd7d-063fd18953fc8a-4c657b58-1638720-19a0b18d44ce35%22%2C%22props%22%3A%7B%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22platform%22%3A%22PC%22%7D%7D; Qs_lvt_73105=1761122768; _jzqckmp_v2=1/; smidV2=20251022164608e186645d8628bee486a4d95039662d74007e71e5e6bf82200; i_h_s=%25E4%25B9%25A6%25E5%258C%2585; Hm_lvt_d4bb30b3ba58b04cd3d04be8ebb57263=1761122769; HMACCOUNT=6ADDF01C2801D70F; _qzja=1.1160944136.1761122768543.1761122768543.1761122768543.1761123550005.1761123894891.0.0.0.4.1; _qzjb=1.1761122768543.4.0.0.0; _qzjc=1; _qzjto=4.1.0; Qs_pv_73105=9999446217126684%2C398392608469106700%2C3751520961269061600%2C148286681435495460; Hm_lpvt_d4bb30b3ba58b04cd3d04be8ebb57263=1761123896; .thumbcache_c6ed5383e076d23f8144e9f7663f043c=kETL0l65GWpzqphaO01IIUphFz5OxXqTyQNI0bVi86ODUWiW/e90BbaUaYBkmw3OXe1dpv/Fw1OaMxd+ycd1Lg%3D%3D"
}
点击查看代码
def get_page_data(page_index):
    """根据页码发起请求,并返回原始响应字符串"""
    data = {
        "k": SEARCH_KEYWORD,
        "c": "",
        "isava": "",
        "act": "",
        "promotion": "",
        "actType": "",
        "ruleNo": "",
        "yunType": "",
        "isColl": "1",
        "isMatch": "",
        "ifPickup": "",
        "goodsType": "",
        "markFlag": "",
        "sorCol": "",
        "sorTye": "",
        "pageIndex": str(page_index),  # 动态页码
        "pageSize": str(PAGE_SIZE)
    }

    try:
        resp = requests.post(BASE_URL, headers=headers, data=data, timeout=10)
        resp.raise_for_status()  # 检查状态码是否 200
        return resp.text
    except requests.exceptions.RequestException as e:
        print(f"请求第 {page_index} 页失败: {e}")
        return None

点击查看代码
while len(all_products) < MAX_ITEMS:
    # 1. 发起请求
    raw_response = get_page_data(current_page)

    if raw_response is None:
        print("请求失败或超时,停止爬取。")
        break

    # 2. 解析数据
    names, prices = parse_html_content(raw_response)

    # 检查是否还有商品
    if not names:
        print("未检测到更多商品,提前结束。")
        break

    # 3. 存储数据
    new_products = []
    for name, price in zip(names, prices):
        if len(all_products) < MAX_ITEMS:
            all_products.append({
                "name": name.strip(),
                "price": price.strip()
            })
            new_products.append(name.strip())
        else:
            break

    print(f"抓取到 {len(new_products)} 项商品。")
    print(f"当前累计商品数量: {len(all_products)} / {MAX_ITEMS}")

    # 4. 准备下一页
    current_page += 1

运行结果

image

image

实验心得
(1)找商品数据接口找了很久(网页内容是通过 JavaScript 动态加载的,真实的商品信息是浏览器加载后由 JS 异步请求接口(API) 获取的,若要静态获取数据要找真实的数据请求接口),然后还要配自己的cookie(小网站还是做了点反爬的,令人感慨)。
(2)初次爬取时发现有漏爬内容,后续发现商品名称可能有两行,于是修改正则表达式加入[^"]*,表示匹配任意数量(包括零个)的非双引号字符。

作业③

网页图片批量下载实验

实验要求
爬取一个给定网页(https://news.fzu.edu.cn/yxfd.htm)的所有JPEG、JPG或PNG格式图片文件 输出信息:将自选网页内的所有JPEG、JPG或PNG格式文件保存在一个文件夹中

思路
1.查看网页中图片位置,发现它们都在"div class=img slow"中,可以用re库的find_all来匹配它们
2.注意到每张图的后缀可能不同,写正则化表达式时要添加.(?:jpg|jpeg|png)。
以下为网页的内容:
image

核心代码

点击查看代码
# 3. 从 <div class="img slow"> 中提取所有 <img src="...">
# 支持 jpg/jpeg/png 格式
pattern_img = r'<div[^>]*class="img\s+slow"[^>]*>.*?<img[^>]+src="([^"]+\.(?:jpg|jpeg|png))"'
img_urls = re.findall(pattern_img, html, re.IGNORECASE | re.S)

if not img_urls:
    print("未找到任何图片")
    exit()

结果

image

image
与网页中出现的图片数量及画面一致。
实验心得
(1)没有反爬机制,泥福还是太善良了
(2)正则表达式的读写有时十分复杂,需要大量实践

代码保存:
https://gitee.com/liu-yi-huang/data_project/tree/master/作业1

posted @ 2025-10-27 14:19  流留六刘  阅读(0)  评论(0)    收藏  举报