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管理器(基于内存)

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 网页解析

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电影。

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)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moutai码哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值