Python爬虫-经典案例详解

爬虫一般指从网络资源的抓取,通过Python语言的脚本特性,配置字符的处理非常灵活,Python有丰富的网络抓取模块,因而两者经常联系在一起Python就被叫作爬虫。爬虫可以抓取某个网站或者某个应用的内容提取有用的价值信息。有时还可以模拟用户在浏

览器或app应用上的操作行为,从而实现程序自动化。

1、爬虫架构

爬虫架构通常由5个部分组成,分别是调度器、URL管理器、网页下载器、网页解析器、应用程序。

  • 调度器:相当电脑的CPU,主要负责调度URL管理器、下载器、解析器之间的协调工作。
  • URL管理器:包括待爬取的URL地址和已爬取的URL地址,防止重复抓取URL和循环抓取URL。实现URL管理器通常有三种方式,通过内存、数据库、缓存方式实现。
  • 网页下载器:通过传入一个URL地址来下载网页,将网页转换成一个字符串,网页下载器有urllib2(Python官方基础模块)包括需要登录、代理、和cookie,requests(第三方包)。
  • 网页解析器:用于某个网页字符串进行解析,可以按照我们的要求来提取出有用的信息,也可以根据DOM树的解析方式来解析。常用的解析器有html.parser(python自带的)、beautifulsoup(也可以使用python自带的html.parser进行解析,也可以使用lxml进行解析,相对于其他几种来说要强大一些)、lxml(可以解析 xml 和 HTML),通过html.parser 和 beautifulsoup 以及 lxml 都是以DOM 树的方式进行解析。
  • 应用程序:用于从网页中提取的有用数据组成的一个应用。

2、爬虫实现

2.1、Url管理器(基于内存)

python 复制代码
class UrlManager():
    """
     url 管理器,用来装载网址所有地址
    """

    def __init__(self):
        # 新url 集合
        self.new_urls = set()
        # 旧url 集合
        self.old_urls = set()

    def add_new_url(self, url):
        """
        添加新的url到集合
        :param url: url
        :return:
        """
        if url is None or len(url) == 0:
            return
        if url in self.new_urls or url in self.old_urls:
            return
        self.new_urls.add(url)

    def add_new_urls(self, urls):
        """
        批量添加urls
        :param urls: url
        :return:
        """
        if urls is None or len(urls) == 0:
            return
        for url in urls:
            self.add_new_url(url)

    def get_url(self):
        """
        获取url: 从new_urls集合获取url,放入到old_urls
        :return:
        """
        if self.has_new_url():
            url = self.new_urls.pop()
            self.old_urls.add(url)
            return url
        else:
            return None

    def has_new_url(self):
        """
        判断是否有新的url
        :return:
        """
        return len(self.new_urls) > 0

if __name__ == '__main__':
    url_manager = UrlManager()
    url_manager.add_new_url('url1')
    url_manager.add_new_urls(['url1','url2'])
    print(url_manager.new_urls, url_manager.old_urls)

    print("#" * 30)
    new_url = url_manager.get_url()
    print(url_manager.new_urls, url_manager.old_urls)

    print("#" * 30)
    new_url = url_manager.get_url()
    print(url_manager.new_urls, url_manager.old_urls)

    print("#" * 30)
    print(url_manager.has_new_url())

2.2 网页解析

python 复制代码
import re
from utils import url_manager
import requests
from bs4 import BeautifulSoup


def download_all_urls(root_url):
    """
    爬取根网址所有页面的url
    :param root_url: 根网址地址
    :return:
    """
    urls = url_manager.UrlManager()
    urls.add_new_url(root_url)

    fout = open("craw_all_pages.txt", "w", encoding="utf-8")

    while urls.has_new_url():
        curr_url = urls.get_url()
        r = requests.get(curr_url, timeout=5)
        r.encoding = "utf-8"
        if r.status_code != 200:
            print("error, return status_code is not 200", curr_url)
            continue
        soup = BeautifulSoup(r.text, "html.parser", from_encoding="utf-8")
        title = soup.title.string

        fout.write("%s\t%s\n" % (curr_url, title))
        fout.flush()
        print("success: %s, %s, %d" % (curr_url, title, len(urls.old_urls)))

        links = soup.find_all("a")
        for link in links:
            href = link.get("href")
            if href is None:
                continue
            #模式匹配
            pattern = r'^https://www.runoob.com/python/\s+.html$'
            if re.match(pattern, href):
                urls.add_new_url(href)
    fout.close()

if __name__ == '__main__':
    #定义根网址url
    root_url = "https://www.runoob.com/python/python-tutorial.html"
    download_all_urls(root_url)

3、经典案例

例如:读取某网站Top250电影。

python 复制代码
import pprint
import json
import requests
from bs4 import BeautifulSoup
import pandas as pd

"""
# requests 请求网站地址
# beautifulsoup4 解析网址的elements(div,class,<a>,<img> id)等
# pandas 将数据写入到excel
# 其他额外安装包openpyxl
"""

# 构造分页数字列表(步长/pageSize/step=25)
page_indexs = range(0, 250, 25)
list(page_indexs)

def download_all_htmls(root_url, headers):
    """
    下载所有页面的html内容,用于后续分析
    :return:
    """
    htmls = []
    for idx in page_indexs:
        url = "%s?start=%d&filter=" % (root_url, idx)
        # url = f"https://movie.douban.com/top250?start={idx}&filter="
        print("craw html:", url)
        r = requests.get(url, timeout=5, headers=headers)
        if r.status_code != 200:
            raise Exception("error")
        htmls.append(r.text)

    return htmls


def parse_single_html(html_doc):
    soup = BeautifulSoup(html_doc, "html.parser")
    article_items = (
        soup.find("div", class_="article")
        .find("ol", class_="grid_view")
        .find_all("div", class_="item")
    )
    datas = []
    for item in article_items:
        rank = item.find("div", class_="pic").find("em").get_text()
        info = item.find("div", class_="info")
        title = info.find("div", class_="hd").find("span", class_="title").get_text()
        stars = (
            info.find("div", class_="bd")
            .find("div", class_="star")
            .find_all("span")
        )
        rating_star = stars[0]["class"][0]
        rating_num = stars[1].get_text()
        comments = stars[3].get_text()

        datas.append({
            "rank": rank,
            "title": title,
            "rating_star": rating_star.replace("rating", "").replace("-t", ""),
            "rating_num": rating_num,
            "comments": comments.replace("人评价", "")
        })

    return datas


def save_to_excel(all_datas):
    """
    保存解析后数据到excel
    :param all_datas: 传人数据
    :return:
    """
    # print table
    df = pd.DataFrame(all_datas)
    print(df)
    df.to_excel("豆瓣电影TOP250.xlsx")


if __name__ == '__main__':
    # 模拟用户行为
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
    }
    # 定义根网址url
    root_url = "https://movie.douban.com/top250"
    htmls = download_all_htmls(root_url, headers)

    # beatiful print text
    pprint.pprint(parse_single_html(htmls[0]))

    # extend迭代添加到list,保存到excel
    all_datas = []
    for html in htmls:
        all_datas.extend(parse_single_html(html))

    print(len(all_datas))
    save_to_excel(all_datas)
相关推荐
数据智能老司机3 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机4 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机4 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机4 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i5 小时前
drf初步梳理
python·django
每日AI新事件5 小时前
python的异步函数
python
这里有鱼汤6 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python
databook15 小时前
Manim实现脉冲闪烁特效
后端·python·动效
程序设计实验室15 小时前
2025年了,在 Django 之外,Python Web 框架还能怎么选?
python
倔强青铜三17 小时前
苦练Python第46天:文件写入与上下文管理器
人工智能·python·面试