爬虫(进阶),爬取网页信息并写入json文件

本文介绍了一个具体的爬虫实现案例,利用Python的requests库和BeautifulSoup库从目标网站爬取案例文章,包括标题、内容及发布时间等信息,并解析了不同类型的案例页面结构。此外,还介绍了如何通过POST请求获取更多案例链接。
import requests  # python HTTP客户端库,编写爬虫和测试服务器响应数据会用到的类库
import re
import json
from bs4 import BeautifulSoup
import copy
print('正在爬取网页链接……')
List = []
for page in range(8):
    if page == 0:
        url = 'http://usagz.bailitop.com/public/'
    else:
        url = 'http://usagz.bailitop.com/public/' + str(page + 1) + '.html'
    print('-----------正在爬取第' + str(page + 1) + '页------')
    html = requests.get(url)
    html.raise_for_status()
    html.encoding = 'utf-8'
    try:
        soup = BeautifulSoup(html.text, 'html.parser')
        soup = str(soup)
        # 正则表达式找到网页链接
        href = re.compile('http://usagz\.bailitop\.com/public/\d*/\d*\.html')
        URLs = re.findall(href, soup)
        flag = 0
        # 过滤前面重复的3条
        for webUrl in URLs:
            flag = flag + 1
            if flag > 4:
                List.append(webUrl)
                # 每个页面15条数据
    except Exception as e:
        print(e)

print(List)
# 创建字典
data = {'title': '', 'content': '', 'time': ''}
dataList = []

for webSite in List:
    print('\n')
    html = requests.get(webSite)
    html.raise_for_status()
    html.encoding = 'utf-8'
    try:
        soup = BeautifulSoup(html.text, 'html.parser')
        soup = str(soup)
        # 标题
        reg = re.compile('<div id="CLM_one">.*<h1>(.*)</h1>.*</div>', re.S)
        title = re.findall(reg, soup)
        title = title[0]
        if title.count('img'):
            # 去前面的标签
            title = title.split('>', 1)
            title = title[1]
            # 去后面的标签
            title = title.split('<', 1)
            title = title[0]

        # 日期
        reg = re.compile('\d{4}-\d\d-\d\d')
        date = re.findall(reg, soup)
        date = date[0]

        # 正文
        reg = re.compile('<div class="center_main">(.*)</div>.*<div class="text-c" id="pages"', re.S)
        content = re.findall(reg, soup)
        content = content[0]
        # 替换文本
        content = content.replace('百利天下', '智课')
        # 更新字典信息
        data['title'] = title
        data['content'] = content
        data['time'] = date
        # 加入List
        dataList.append(data)
        # 更改字典地址
        data = copy.copy(data)
    except Exception as e:
        print(e)
# 转换json,注意编码
jsonList = json.dumps(dataList, ensure_ascii=False)
print(jsonList)
# 写入文件
with open("record.json", "w", encoding='utf-8') as f:
    f.write(jsonList)
    print("加载入文件完成...")


import requests  # python HTTP客户端库,编写爬虫和测试服务器响应数据会用到的类库
import re
import json
from bs4 import BeautifulSoup
import copy
import urllib.request
import urllib.parse

def downloadPostPage(url, dictdata, headers, charset='utf-8', reqnum=5):
    data = bytes(urllib.parse.urlencode(dictdata), encoding=charset)
    req = urllib.request.Request(url, data, headers=headers, method='POST')
    info = None
    try:
        response = urllib.request.urlopen(req)
        info = response.read().decode(charset)
    except Exception as e:
        # 服务器错误
        print(e)
    return info

if __name__ == '__main__':
    dic = {
        'title': '标题',
        'abstract': '摘要',
        'studentInfo': {
            'study_exp': '最高教育经历',
            'school_type': '院校类型',
            # 成绩分类 托福 小托福 SSAT SLEP
            'grade': []
        },
        'offerInfo': {
            'school': 'value1',
            'degree': 'value2',
            'date': 'value2'
        },
        'paragraphs': [
            {'title': '标题1', 'content': 'content1'},
            {'title': '标题2', 'content': 'content2'},
            {'title': '标题3', 'content': 'content3'},
            {'title': '标题4', 'content': 'content4'},
            {'title': '标题5', 'content': 'content5'}
        ]
    }
    dicList = []
    urlList = []
    url = 'http://case.bailitop.com/cases/yuanxiaoajax.shtml'
    headers = {
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "X-Requested-With": "XMLHttpRequest",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    }
    for jzgd in range(1):
        dictdata = {
            'jzgd': 4, 'type': 2, 'mbcountry': '美国', 'mbdegree': '高中', 'univ': '', 'major': '', 'gpa': '',
            'toefl': '',
            'ielts': ''
        }
        # 请求url , 请求参数dictdata ,   构造的头headers  , 请求次数reqnum
        info = downloadPostPage(url, dictdata, headers=headers, reqnum=1)
        jsonLoads = json.loads(info)[0]
        reg = re.compile('http://case\.bailitop\.com/yuanxiao/\d*\.shtml')
        urlList = urlList + re.findall(reg, jsonLoads)
    print(urlList)
    for webSite in urlList:
        print('\n')
        html = requests.get(webSite)
        html.raise_for_status()
        html.encoding = 'utf-8'
        try:
            data1 = {'type': '', 'value': ''}
            soup = BeautifulSoup(html.text, 'html.parser')

            # 正文
            soupContent = soup.find("div", class_="anli_wenzhang")

            title1 = str(soupContent.p)
            reg = re.compile('【(.*)】', re.S)
            title = re.findall(reg, title1)
            # print(title)
            flag = 1
            content1 = ''
            content2 = ''
            content3 = ''
            content4 = ''
            content5 = ''
            title2 = ''
            title3 = ''
            title4 = ''
            title5 = ''
            for sibling in soupContent.p.next_siblings:
                sibling = str(sibling)
                sibling = sibling.replace('\r', '')
                sibling = sibling.replace('\n', '')
                if sibling.count('【'):
                    flag = flag + 1
                    reg = re.compile('【(.*)】', re.S)
                    if flag == 2:
                        title2 = re.findall(reg, sibling)
                    elif flag == 3:
                        title3 = re.findall(reg, sibling)
                    elif flag == 4:
                        title4 = re.findall(reg, sibling)
                    elif flag == 5:
                        title5 = re.findall(reg, sibling)
                else:
                    if flag == 1:
                        if content1 == '':
                            content1 = content1 + sibling
                        else:
                            content1 = content1 + '\n' + sibling
                    elif flag == 2:
                        if content2 == '':
                            content2 = content2 + sibling
                        else:
                            content2 = content2 + '\n' + sibling
                    elif flag == 3:
                        if content3 == '':
                            content3 = content3 + sibling
                        else:
                            content3 = content3 + '\n' + sibling
                    elif flag == 4:
                        if content4 == '':
                            content4 = content4 + sibling
                        else:
                            content4 = content4 + '\n' + sibling
                    elif flag == 5:
                        if content5 == '':
                            content5 = content5 + sibling
                        else:
                            content5 = content5 + '\n' + sibling
            content1 = content1.replace('</p>', '')
            content1 = content1.replace('<p>', '')
            content2 = content2.replace('</p>', '')
            content2 = content2.replace('<p>', '')
            content3 = content3.replace('</p>', '')
            content3 = content3.replace('<p>', '')
            content4 = content4.replace('</p>', '')
            content4 = content4.replace('<p>', '')
            content5 = content5.replace('</p>', '')
            content5 = content5.replace('<p>', '')
            content3 = content3.replace('百利天下', '智课')
            content4 = content4.replace('百利天下', '智课')
            content5 = content5.replace('百利天下', '智课')
            content1 = content1.replace('\u3000', '')
            content2 = content2.replace('\u3000', '')
            content3 = content3.replace('\u3000', '')
            content4 = content4.replace('\u3000', '')
            content5 = content5.replace('\u3000', '')
            content5 = content5.replace('\n', '')
            content5 = content5.replace('<br/>', '')
            if content5.count('<p'):
                reg = re.compile('(.*?)<p', re.S)
                content5 = re.findall(reg, content5)
            dic['paragraphs'][0]['title'] = title[0]
            dic['paragraphs'][1]['title'] = title2[0]
            dic['paragraphs'][2]['title'] = title3[0]
            dic['paragraphs'][3]['title'] = title4[0]
            dic['paragraphs'][4]['title'] = title5[0]
            dic['paragraphs'][0]['content'] = content1
            dic['paragraphs'][1]['content'] = content2
            dic['paragraphs'][2]['content'] = content3
            dic['paragraphs'][3]['content'] = content4
            dic['paragraphs'][4]['content'] = content5

            soup = str(soup)

            # 摘要  有个\r\n 手动删
            reg = re.compile('<p><strong>摘要</strong>:(.*)</p>.*<div.*class="zixun">', re.S)
            abstract = re.findall(reg, soup)[0]
            abstract = abstract.replace('百利天下', '智课')
            dic['abstract'] = abstract
            print(abstract)

            # title 个别<strong>未解决,手动删
            reg = re.compile('<h2>(.*)</h2>', re.S)
            title = re.findall(reg, soup)[0]
            if title.count('<strong') == 1:
                reg = re.compile('<strong.*?>(.*)', re.S)
                title = re.findall(reg, title)[0]
                title = title.replace('</strong>', '')
            dic['title'] = title
            print(title)

            # offer详情
            reg = re.compile(
                '<p>录取院校:(.*)</p>\n<p></p>\n<p>授予学位:(.*)</p.*<p>入学时间:(.*?)</p>\n</div>\n<div class="g_btns">', re.S)
            offerInfo = re.findall(reg, soup)[0]
            dic['offerInfo']['school'] = offerInfo[0]
            dic['offerInfo']['degree'] = offerInfo[1]
            dic['offerInfo']['date'] = offerInfo[2]
            print(offerInfo)

            # 学生档案
            reg = re.compile(
                '<p>最高教育经历:(.*)</p>\n<p>院校类型:(.*)</p>\n<p></p>\n<p>语言成绩:(.*?)</p>', re.S)
            studentInfo = re.findall(reg, soup)
            if len(studentInfo) == 0:
                # 只有 最高教育经历 院校类型
                reg = re.compile(
                    '<p>最高教育经历:(.*)</p>\n<p>院校类型:(.*?)</p>\n<p></p>', re.S)
                studentInfo = re.findall(reg, soup)
                if len(studentInfo) == 0:
                    # 只有 院校类型 语言成绩
                    reg = re.compile(
                        '<p>院校类型:(.*?)</p>\n<p></p>\n<p>语言成绩:(.*?)</p>', re.S)
                    studentInfo = re.findall(reg, soup)
                    studentInfo = studentInfo[0]
                    grade = studentInfo[1]
                    grade = grade.replace('&nbsp', ' ')
                    grade = grade.replace(';', '')
                    grade = grade.replace('  ', ' ')
                    dic['studentInfo']['study_exp'] = ''
                    dic['studentInfo']['school_type'] = studentInfo[0]
                    # dic['studentInfo']['grade'] = grade
                    print('院校类型:', studentInfo[0], '||语言成绩:', grade)
                    reg = re.compile(r' ')
                    gradeList = re.split(reg, grade)
                    for n in range(int((len(gradeList) - 1) / 2)):
                        data1['type'] = gradeList[n * 2]
                        data1['value'] = gradeList[n * 2 + 1]
                        dic['studentInfo']['grade'].append(data1)
                        data1 = copy.deepcopy(data1)
                else:
                    studentInfo = studentInfo[0]
                    dic['studentInfo']['study_exp'] = studentInfo[0]
                    dic['studentInfo']['school_type'] = studentInfo[1]
                    # dic['studentInfo']['grade'] = ''
                    print('最高教育经历:', studentInfo[0], '||院校类型:', studentInfo[1])
            else:
                studentInfo = studentInfo[0]
                grade = studentInfo[2]
                grade = grade.replace('&nbsp', ' ')
                grade = grade.replace(';', '')
                grade = grade.replace('  ', ' ')
                dic['studentInfo']['study_exp'] = studentInfo[0]
                dic['studentInfo']['school_type'] = studentInfo[1]
                # dic['studentInfo']['grade'] = grade
                print('最高教育经历:', studentInfo[0], '||院校类型:', studentInfo[1], '||语言成绩:', grade)
                reg = re.compile(r' ')
                gradeList = re.split(reg, grade)
                for n in range(int((len(gradeList) - 1) / 2)):
                    data1['type'] = gradeList[n * 2]
                    data1['value'] = gradeList[n * 2 + 1]
                    dic['studentInfo']['grade'].append(data1)
                    data1 = copy.copy(data1)

            dicList.append(dic)

            dic = copy.deepcopy(dic)
            dic['studentInfo']['grade'].clear()
        except Exception as e:
            print(e)

    jsonList = json.dumps(dicList, ensure_ascii=False)
    print(jsonList)
    # 写入文件
    with open("CaseRecord.json", "w", encoding='utf-8') as f:
        f.write(jsonList)
        print("加载入文件完成...")

<think>嗯,用户需要获取使用网络爬虫爬取学校官网新闻信息的方法或教程。这是一个相对具体的技术需求,用户可能是学生或者初学者,想通过实践学习爬虫技术。分析之前的对话历史和用户需求:用户引用了四个相关参考资料,其中引用1和4介绍了基础爬取流程,引用2提到静态网页与动态网页的区别,引用3则展示了完整的时间跨度和数据清洗案例。用户明确要求“爬取学校官网新闻信息”的方法,说明ta需要实战指导而非理论探讨。考虑采用递进式教学:新手容易卡在环境配置和基础解析上,所以需明确说明如何用Python创建项目、安装库(requests/BeautifulSoup)、分析网页结构(F12开发者工具)、定位标题和链接的CSS选择器。再逐步引入分页处理、反爬策略等进阶技巧。结合引用资料的专业点:引用2特别提到静态网页的数据可见性优势——这点要作为基础案例。引用3展示了多年度连续爬取的可行性,考虑用分页器实现。引用4的样例代码虽然简单但包含关键库的导入,可以借鉴。潜在难点预判:学校官网可能有三种结构:传统静态页(如引用1/4)、伪静态JS渲染页(需Selenium)、API动态加载(需抓包分析)。准备优先教授静态页方案(覆盖90%学校官网),再补充说明其他情况的应对策略。安全合规提示:必须强调Robots协议(引用2未提及),建议添加User-Agent轮换等伦理操作,避免频繁请求造成官网访问压力。结构化教程设计:计划用四步递进讲解:基础静态页爬取→分页逻辑→数据清洗存储→动态页应对。用代码注释增加可读性,添加常见错误排查(如标签变更、编码问题),这些在引用3中有实践经验。</think> 好的,我们来详细讲解如何使用 Python 网络爬虫爬取学校官网新闻信息。这是一个非常常见的入门级爬虫项目,非常适合学习静态网页爬取。基于您提供的参考资料和需求,我将分步骤介绍核心方法和技巧: **核心思路:** 大部分学校官网的新闻列表页和详情页都是`静态网页`,即页面内容直接包含在初始 HTML 文件中。这意味着我们可以直接通过请求 URL,获取 HTML 源码,然后从中提取(解析)我们需要的信息(标题、链接、发布日期、正文等)。 **所需工具 (Python 库):** 1. **`requests`**: 用于向目标网站发送 HTTP 请求,获取网页的 HTML 源代码。 (必备) 2. **`BeautifulSoup (bs4)`**: 一个强大的 HTML/XML 解析库,用于从获取到的 HTML 中提取(解析)所需的数据(如标题、链接)。 (必备) 3. **(可选) `lxml`**: 另一个高效的解析库,可以作为 BeautifulSoup 的底层解析引擎(速度快)。 4. **(可选) `re` (正则表达式)**: 有时对于复杂或不规则的字符串匹配提取(比如从一大段文本中抽日期),正则表达式很有用。但 BeautifulSoup 在大多数情况下足够。 5. **(可选) `pandas` / `csv` / `sqlite3` / `pymysql`**: 用于将提取到的数据存储到 CSV 文件、Excel 或数据库中。引用 [3] 和 [4] 提到了数据库存储。 6. **(可选) `time` / `random`**: 用于控制请求频率,在请求之间加入延时,避免对服务器造成过大压力或被反爬机制阻止。 **步骤详解:** 1. **目标分析与规划:** * **确定目标网站:** 找到您学校官网的新闻中心或通知公告版块的 URL。例如 `https://www.xxx.edu.cn/news/` 或 `https://news.xxx.edu.cn/`。 * **观察页面结构:** * 打开目标页面,右键 -> “检查”(或 “审查元素”)。 * 查看新闻列表:每条新闻项通常包含在特定的 HTML 标签(如 `<div class="news-item">`, `<li>`, `<article>`)内。 * 识别需要的数据:在每个新闻项里,找到标题、链接(通常是 `<a href="...">` 标签)、发布日期、摘要等的 HTML 标签和属性(`class`, `id`)。 * **关键点:** 找到能唯一标识新闻项容器的选择器(如 `div.news-list li` 或 `ul#newsList > li`),以及内部元素的选择器(如 `a.title` 获取标题链接,`span.date` 获取日期)。 * **观察分页:** 查看列表页是否有分页(“上一页”、“下一页”、页码)。查看点击“下一页”时 URL 的变化规律(如 `?page=2`, `/news/list_2.html`)。 2. **获取网页源码 (Requests):** ```python import requests # 目标列表页 URL (替换为你的学校新闻列表页 URL) list_url = "https://news.example.edu.cn/list.htm" # 通常是首页 # 设置请求头,模拟浏览器访问,可以降低被反爬的概率 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36' } try: # 发送 GET 请求 response = requests.get(list_url, headers=headers) # 检查请求是否成功 (状态码 200 表示成功) response.raise_for_status() # 如果请求失败会抛出异常 # 获取网页源代码,设置正确的编码(如果网页是 GBK 编码,则用 'gbk') html_content = response.content.decode('utf-8') # 大多数网页用 utf-8 # 现在 html_content 包含了整个新闻列表页的 HTML 源码 except requests.exceptions.RequestException as e: print(f"请求发生错误: {e}") html_content = None ``` 3. **解析 HTML 提取数据 (BeautifulSoup):** ```python from bs4 import BeautifulSoup if html_content: # 使用 BeautifulSoup 解析 HTML,'lxml' 是推荐的解析器(速度快),需安装 pip install lxml # 如果没有安装 lxml,使用 'html.parser'(内置,但稍慢) soup = BeautifulSoup(html_content, 'lxml') # 或者 'html.parser' # 找到包含所有新闻项的容器元素(通过之前观察到的选择器) # 例:假设每个新闻项都在 <li class="news-item"> 标签里 news_items = soup.find_all('li', class_='news-item') # 存储提取结果的列表 news_data = [] # 遍历每个新闻项 for item in news_items: # 1. 提取标题和链接:通常在 <a> 标签里 title_link = item.find('a') # 找到第一个 a 标签,通常包含标题和链接 if title_link: news_title = title_link.get_text(strip=True) # 获取标签内纯文本,去除两端空白 news_url = title_link.get('href') # 获取 href 属性值(链接) # 注意:链接可能是相对路径(如 /news/123.html),需要补全为绝对 URL if news_url and not news_url.startswith(('http://', 'https://')): # 根据网站实际情况拼接基础 URL base_url = "https://news.example.edu.cn" # 替换为你的新闻网站基础 URL news_url = base_url.rstrip('/') + '/' + news_url.lstrip('/') # 2. 提取发布日期:通常在特定的标签里,如 <span class="date"> date_tag = item.find('span', class_='date') publish_date = date_tag.get_text(strip=True) if date_tag else "日期未知" # 3. (可选) 如果列表页有摘要,同样方式提取 # summary_tag = ... # news_summary = ... # 将提取的信息存入字典,然后加到列表中 news_data.append({ 'title': news_title, 'url': news_url, 'date': publish_date, # 'summary': news_summary }) # 此时 news_data 包含了当前列表页所有新闻的标题、链接和日期 ``` 4. **处理分页:** * 根据第 1 步观察到的分页 URL 规则生成所有列表页的 URL。 * 通常可以通过一个 `for` 循环控制页码(`page=1, 2, 3, ..., N`)。 * 在每爬取一页后,最好加入短暂延时(例如 `time.sleep(1)`),以示礼貌,避免被封 IP。 ```python import time # 总页数 (需要观察确定,或者尝试请求直到找不到"下一页"按钮) total_pages = 5 # 假设总共有5页 all_news = [] # 存储所有页面爬取的数据 for page in range(1, total_pages + 1): # 构造每一页的 URL (根据实际规则构造) list_url = f"https://news.example.edu.cn/list_{page}.htm" # 示例 1 # 或 list_url = f"https://news.example.edu.cn/news/?page={page}" # 示例 2 print(f"正在爬取第 {page} 页: {list_url}") try: response = requests.get(list_url, headers=headers) response.raise_for_status() soup = BeautifulSoup(response.content, 'lxml') # 提取当前页的新闻数据 (复用第 3 步的代码) page_news = ... # 像第3步那样解析出本页的news_data all_news.extend(page_news) # 加到总列表中 # 重要!随机延时 1-3 秒 time.sleep(random.uniform(1, 3)) except Exception as e: print(f"爬取第 {page} 页失败: {e}") # 现在 all_news 包含了指定页数范围的所有新闻条目(标题、链接、日期) ``` 5. **爬取新闻详情 (可选,如果需要正文内容):** * 遍历 `all_news` 中的每一条新闻。 * 使用 `requests` 获取 `news_url`(即每条新闻的链接 URL)。 * 再次用 `BeautifulSoup` 解析新闻详情页 HTML。 * 定位到包含新闻正文的容器元素(通常是 `<div class="article-content">` 或 `id="content"`),提取其内容 `.get_text()` 或保留必要的 HTML 标签。 ```python for news in all_news: detail_url = news['url'] print(f"正在爬取详情页: {detail_url}") try: detail_resp = requests.get(detail_url, headers=headers) detail_resp.raise_for_status() detail_soup = BeautifulSoup(detail_resp.content, 'lxml') # 找到正文容器 (通过观察确定选择器) content_div = detail_soup.find('div', class_='article-content') # 或者 content_div = detail_soup.find('div', id='content') if content_div: # 去除不需要的标签(如脚本、样式、多余的 div/span 等) for element in content_div(['script', 'style', 'div.aside', 'iframe']): # 根据实际情况调整要删除的标签 element.decompose() # 获取处理后的正文 HTML 或纯文本 news_content_html = str(content_div) # 获取包含HTML标签的内容 news_content_text = content_div.get_text(strip=True) # 获取纯文本(大量空格换行会被压缩) # 或者用 content_div.get_text(separator='\n', strip=True) 保留换行 # 添加到 news 字典中 news['content_html'] = news_content_html # 或者只存一个,如 'content' news['content_text'] = news_content_text # 延时 time.sleep(random.uniform(2, 4)) except Exception as e: print(f"爬取详情页 {detail_url} 失败: {e}") news['content'] = "获取失败" ``` 6. **数据存储:** * **CSV 文件 (简单推荐):** ```python import csv # 以写方式打开文件 with open('school_news.csv', 'w', newline='', encoding='utf-8-sig') as csvfile: # utf-8-sig 解决Excel中文乱码 fieldnames = ['title', 'url', 'date', 'content_text'] # 指定要保存的字段 writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() # 写入表头 for news in all_news: writer.writerow(news) # 写入每条数据 ``` * **数据库 (如 MySQL - 需要安装 pymysql):** ```python import pymysql # 连接数据库 (参数替换为你的数据库信息) conn = pymysql.connect( host='localhost', user='your_username', password='your_password', database='school_news_db', charset='utf8mb4' # 支持存储emoji等更全的字符 ) cursor = conn.cursor() # 创建表 (如果不存在) create_table_sql = """ CREATE TABLE IF NOT EXISTS news ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, url VARCHAR(500) NOT NULL, publish_date DATE, content_text TEXT, UNIQUE KEY unique_url (url) # 通常URL唯一,防止重复插入 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; """ cursor.execute(create_table_sql) # 插入数据 insert_sql = """ INSERT IGNORE INTO news (title, url, publish_date, content_text) VALUES (%s, %s, %s, %s) """ for news in all_news: # 尝试转换日期字符串为数据库兼容的 DATE 格式 (如 "YYYY-MM-DD") # 可能需要使用 datetime.strptime 解析原始日期字符串 # 这里简单起见,假设news['date']是像"2023-08-10"这样的格式 data = (news['title'], news['url'], news['date'], news.get('content_text', '')) cursor.execute(insert_sql, data) # 提交事务关闭连接 conn.commit() cursor.close() conn.close() ``` * **JSON 文件:** ```python import json with open('school_news.json', 'w', encoding='utf-8') as f: json.dump(all_news, f, ensure_ascii=False, indent=4) # 确保中文字符正常显示 ``` **重要注意事项与最佳实践:** 1. **遵守 Robots 协议:** 在爬取任何网站之前,务必查看目标网站的 `robots.txt` 文件 (如 `https://news.example.edu.cn/robots.txt`)。了解哪些路径允许爬取,哪些不允许(如 `Disallow: /search/`)。尊重网站的爬虫规则是基本的网络礼仪和法律要求。引用[2]提到了这是基础之后的进阶内容,但意识必须从开始培养[^2]。 2. **设置合理的请求间隔:** 使用 `time.sleep(random.uniform())` 在请求之间加入随机延时(如 1-5 秒)。**切忌**连续高频率请求,这会给服务器带来很大压力,很可能触发反爬机制导致你的 IP 被封禁。 3. **使用 User-Agent:** 如示例中所示,设置 `User-Agent` 请求头,模拟一个真实的浏览器访问。这是非常基本的反反爬措施。 4. **错误处理:** 如代码示例所示,一定要使用 `try...except` 捕获网络请求失败、解析失败等异常,做好记录(如打印错误信息)。这能让你的爬虫在遇到部分失败时继续运行或优雅退出,而不是整个程序崩溃。 5. **资源管理:** 确保在完成操作(尤其是连接数据库后)后关闭连接。 6. **处理编码:** 目标网站可能使用 `GB2312`、`GBK`、`UTF-8` 等不同编码,`response.text` 有时会误判编码,使用 `response.content.decode('正确编码')` 更可靠。通过查看网页源码中的 `<meta charset="...">` 标签来确定正确编码。 7. **注意反爬:** 除了上面提到的间隔和 UA。有些网站可能有更复杂的反爬: * **Cookies/Session:** 可能需要使用 `requests.Session()` 保持会话。 * **JavaScript 渲染:** 如果目标网站是 **动态网页 (Ajax加载数据)**,使用 `requests` + `BeautifulSoup` 无法获取数据,因为核心数据是 JS 动态加载的。这时就需要用到 **Selenium** 或 **Pyppeteer** 这样的工具来模拟浏览器行为,或者通过浏览器开发者工具的 Network 选项卡分析获取真实数据 API 的请求。引用[2]特别提到了动态网页的区别和后续可以关注的文章[^2]。 * **IP 限制:** 如果单 IP 被封锁太多,可能需要使用 **代理 IP 池**。 **总结:** 爬取学校官网新闻的核心流程是:**分析结构** -> **获取列表页** -> **解析列表页获取标题链接和日期** -> **(可选) 获取详情页解析正文** -> **存储数据 (CSV/DB/JSON)**。务必注意 **遵守 `robots.txt`**、**设置请求间隔**、**使用 User-Agent** 以及 **做好错误处理**。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值