requests + BeautifulSoup + urllib 爬取并下载网站图片到本地(一)

本文介绍了使用requests、BeautifulSoup和urllib库下载网站图片到本地的步骤,包括设置开发环境、分析HTML节点、指定编码格式、获取图片链接和图片名,以及如何将图片保存到本地。

这一篇主要写使用 requests + BeautifulSoup + urllib 下载图片保存到本地,下一篇写下载整站详情页的图片保存到本地(敬请期待)

爬取网络上的数据其实很简单,只要掌握基本逻辑就好了。

  1. 找到网站;
  2. 分析所需数据的 HTML 节点;
  3. 把数据下载到本地或者存储到数据库

那好,废话不多说,开始吧!


准备工作
  • 开发环境:Windows,Pycharm,Request,BeautifulSoup,urllib
  • 需要一定的 Python 爬虫、HTML 基础
开始动身
  • 明确目标
    本次要爬取的网站是 帅啊(点开看一下,有惊喜哦~[坏笑].png)
    我们需要把网站第一页所有 item 的图片下载到本地

  • 制作爬虫

    1. 由于获取下来的 html 编码格式不对,所以要指定编码格式为 utf-8
    2. 获取页面中每个 item 的图片标签
    3. 循环获取标签的图片链接(src)和图片名(alt)
    4. 下载图片到本地
from bs4 import BeautifulSoup
import requests
import os
import urllib.request
import time

headers = {
    "Cookie": "UM_distinctid=16685e0279d3e0-06f34603dfa898-36664c08-1fa400-16685e0279e133; bdshare_firstime=1539844405694; gsScrollPos-1702681410=; CNZZDATA1254092508=1744643453-1539842703-%7C1539929860; _d_id=0ba0365838c8f6569af46a1e638d05",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
}
path = "D://images/"

def get_links(url):
    wb_data = requests.get(url, headers=headers)  # 加入 headers,避免被网站的反爬机制认为是蜘蛛
    wb_data.encoding = "utf-8"
    soup = BeautifulSoup(wb_data.text, 'lxml')

    links = soup.select(".item-img img")
    if not os.path.exists(path):  # 判断该文件夹是否存在,不存在则创建
        os.mkdir(path)
    for link in links:
        time.sleep(1)  # 暂停一秒,避免访问过快被反爬机制认为是蜘蛛
        img = link.get("src")
        img_name = link.get("alt")
        urllib.request.urlretrieve(img, path + img_name + ".jpg")
        print("-------- downloading ---------")

    print("------ download done -------")

if __name__ == "__main__":

    get_links("http://www.shuaia.net/index.html")
  • 开始爬取

<think>我们面对的任务是爬取网页中的APK文件,需要结合静态解析(requests+BeautifulSoup)和动态渲染(Selenium)两种方法。 根据引用[1]和[2],我们知道BeautifulSoup适合静态网页,而Selenium适合动态渲染的网页。因此,我们需要根据目网页的特点选择合适的方法,或者结合使用。 步骤分析: 1. 解析URL:分析目网页结构,确定APK文件的下载链接可能出现的位置。 2. 查找下载关键词:在页面中寻找包含“下载”、“Download”等关键词的链接或按钮。 3. 智能下载按钮识别策略:除了关键词,可能还需要结合HTML签(如a签的href属性,button的onclick事件等)和CSS类名(如".download-btn")来识别。 4. 模拟点击下载:对于静态链接,可以直接使用requests下载;对于动态生成的链接或需要交互才能出现的下载按钮,使用Selenium模拟点击。 我们可以分两种情况处理: 情况:静态网页(使用requests+BeautifulSoup) - 发送请求获取网页内容。 - 使用BeautifulSoup解析,查找包含下载关键词的链接(如<a>签的文本或属性中包含关键词)。 - 提取到链接后,使用requests下载APK文件。 情况二:动态网页(使用Selenium) - 使用Selenium打开网页,等待页面加载完成(可能需要显式等待)。 - 通过Selenium查找包含下载关键词的按钮或链接(可以通过XPath、CSS选择器等定位元素)。 - 模拟点击该元素(如果点击后触发下载,则浏览器会自动下载;如果点击后出现新的链接,则获取新链接再下载)。 - 有时候点击后文件直接下载,但我们需要知道下载的文件保存到哪里,或者控制下载行为(可以使用浏览器选项设置下载路径)。 然而,有些网站可能同时包含静态和动态内容,因此可能需要结合两种方法。 具体步骤: 、静态模式(requests + BeautifulSoup) 1. 发送请求: ```python import requests from bs4 import BeautifulSoup url = "目网页URL" headers = {'User-Agent': 'Mozilla/5.0'} # 模拟浏览器,避免被反爬 response = requests.get(url, headers=headers) response.encoding = 'utf-8' # 根据实际编码调整 html_content = response.text ``` 2. 解析查找下载链接: ```python soup = BeautifulSoup(html_content, 'html.parser') # 查找所有a签,过滤出包含下载关键词的 download_keywords = ['下载', 'Download', 'download', 'apk'] download_links = [] for a_tag in soup.find_all('a'): # 检查文本或href属性中是否包含关键词 if any(keyword in a_tag.text for keyword in download_keywords) or \ any(keyword in a_tag.get('href', '') for keyword in download_keywords): # 获取绝对URL link = a_tag.get('href') if not link.startswith('http'): # 相对URL转绝对URL link = requests.compat.urljoin(url, link) download_links.append(link) # 此外,还可以查找按钮(button)或者其他元素,但通常下载链接在a签中。 ``` 3. 下载APK文件: ```python for link in download_links: # 检查链接是否以.apk结尾(不定,有些可能是重定向) if link.endswith('.apk'): # 直接下载 apk_response = requests.get(link, headers=headers, stream=True) # 保存文件 filename = link.split('/')[-1] with open(filename, 'wb') as f: for chunk in apk_response.iter_content(chunk_size=1024): if chunk: f.write(chunk) else: # 有可能链接不是直接的apk文件,而是下载页面,需要进步解析(可能需要递归或再次使用静态解析,或者转为动态模式) # 这里可以尝试再次用静态解析,或者根据情况使用动态模式(如果静态解析无法获取,则考虑动态) # 或者,我们可以尝试访问这个链接,看是否会重定向到apk文件 # 但为了避免陷入循环,这里需要谨慎,或者我们可以设置个最大重定向次数。 pass ``` 二、动态模式(Selenium) 1. 配置Selenium: ```python from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 设置浏览器选项(例如:设置下载路径,无头模式等) options = webdriver.ChromeOptions() prefs = { "download.default_directory": "D:\\apk_downloads", # 设置下载路径 "download.prompt_for_download": False, # 禁止下载提示 "download.directory_upgrade": True, "safebrowsing.enabled": True } options.add_experimental_option("prefs", prefs) options.add_argument('--headless') # 无头模式,不显示浏览器 driver = webdriver.Chrome(options=options) ``` 2. 打开网页等待: ```python driver.get(url) # 等待页面加载,使用显式等待等待下载按钮出现 try: # 使用XPath查找包含下载文本的按钮或链接 # 注意:这里可能需要根据实际页面结构调整XPath download_button = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//a[contains(text(),'下载') or contains(text(),'Download')] | //button[contains(text(),'下载') or contains(text(),'Download')]")) ) # 如果找到,模拟点击 download_button.click() except: print("未找到下载按钮") # 点击后,浏览器会开始下载(如果设置了下载路径,文件会保存到指定目录) # 但是,有些网站点击后可能会弹出新窗口,或者需要进步操作,这里需要根据实际情况调整。 # 等待段时间确保下载开始 import time time.sleep(5) # 等待5秒,根据网络情况调整 # 关闭浏览器 driver.quit() ``` 三、智能策略:结合静态和动态 在实际操作中,可以先尝试静态解析,如果静态解析找不到下载链接(或者找到的链接不是直接的apk文件,而是需要跳转的页面),再尝试动态渲染。 伪代码: - 使用requests+BeautifulSoup获取页面,尝试提取apk下载链接。 - 如果提取到直接的apk链接,下载。 - 如果提取到的链接是下载页面(非apk链接),则使用Selenium打开该页面,再次查找下载按钮(这次在下载页面上找)。 - 或者,如果静态解析没有找到任何包含关键词的链接,则直接使用Selenium处理原始URL。 注意:有些网站可能有反爬机制,需要添加headers、代理等。 另外,智能下载按钮识别策略可以包括: - 关键词匹配(多语言:下载、Download、下載等) - 常见class、id匹配(如'download-btn', 'btn-download'等) - 图片alt属性匹配(如果下载按钮是图片) - 链接后缀匹配(如以'.apk'结尾) 由于网站结构多样,可能需要多种策略组合。 四、完整流程示例(结合两种模式) 以下是个综合静态和动态的示例代码框架: ```python import os import requests from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from urllib.parse import urljoin def download_apk_from_url(url, save_dir='apks'): # 第步:尝试静态解析 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'} response = requests.get(url, headers=headers) response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'html.parser') # 查找所有可能的下载链接 download_keywords = ['下载', 'Download', 'download', 'apk'] apk_links = [] for a in soup.find_all('a', href=True): href = a['href'] text = a.get_text(strip=True) # 如果链接文本或href中包含关键词,或者链接以.apk结尾 if any(kw in text for kw in download_keywords) or any(kw in href for kw in download_keywords) or href.endswith('.apk'): absolute_url = urljoin(url, href) apk_links.append(absolute_url) # 过滤出可能是apk文件的链接(以.apk结尾) direct_apk_links = [link for link in apk_links if link.endswith('.apk')] # 如果有直接apk链接,则下载 if direct_apk_links: print("找到直接下载链接:", direct_apk_links) for apk_url in direct_apk_links: download_file(apk_url, save_dir, headers) return # 如果没有直接apk链接,但有些跳转链接,则尝试使用Selenium处理这些跳转链接(或者处理原页面) # 这里我们可以选择第个跳转链接,或者重新用Selenium加载原始页面 # 我们选择重新加载原始页面,因为可能动态生成 print("未找到直接下载链接,尝试动态解析...") # 配置Selenium options = webdriver.ChromeOptions() prefs = { "download.default_directory": os.path.abspath(save_dir), "download.prompt_for_download": False, } options.add_experimental_option("prefs", prefs) # 如果需要无头模式,取消下行的注释 # options.add_argument('--headless') driver = webdriver.Chrome(options=options) driver.get(url) try: # 尝试找到下载按钮点击(这里用XPath,可以根据需要调整) download_button = WebDriverWait(driver, 20).until( EC.element_to_be_clickable((By.XPATH, "//a[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'download') or contains(., '下载')] | " + "//button[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'download') or contains(., '下载')]")) ) download_button.click() # 等待下载完成(这里简单等待,实际中可能需要检查下载目录) time.sleep(10) except Exception as e: print("动态解析失败:", str(e)) finally: driver.quit() def download_file(url, save_dir, headers=None): if headers is None: headers = {} # 确保目录存在 os.makedirs(save_dir, exist_ok=True) # 获取文件名 filename = url.split('/')[-1] filepath = os.path.join(save_dir, filename) # 发送请求下载 r = requests.get(url, headers=headers, stream=True) with open(filepath, 'wb') as f: for chunk in r.iter_content(chunk_size=8192): if chunk: f.write(chunk) print(f"已下载: {filename}") if __name__ == '__main__': target_url = "输入目URL" download_apk_from_url(target_url) ``` 注意: - 上述代码仅为示例框架,实际网站可能需要调整选择器、等待条件等。 - 动态模式中,点击下载按钮后,浏览器会自动下载到指定目录(通过prefs设置)。但是,如果点击按钮后不是直接下载而是打开新页面,则需要进步处理。 - 可能需要处理重定向、验证码、登录等问题,这些情况需要额外处理。 总结: 爬取APK文件需要根据目网站的技术特点选择静态解析或动态渲染,或者结合两者。静态解析速度快,适合简单网站;动态渲染可以处理JavaScript生成的内容。智能下载按钮识别主要依赖关键词和常见属性,但需要不断调整策略以适应不同网站。 相关问题: 1. 如何判断网页是静态还是动态,从而决定使用哪种爬取方式? 2. 在Selenium中,如何处理文件下载时的弹窗? 3. 如何提高爬取APK文件的成功率? 4. 如何验证下载的APK文件是否完整? 5. 如何避免爬虫网站封禁? 希望这些方法能帮助你爬取APK文件。 </think>### Python爬取APK文件的方法详解 结合 `requests+BeautifulSoup` 静态模式和 `Selenium` 动态模式爬取APK文件的核心流程如下: --- #### **、整体流程框架** ```mermaid graph TD A[解析目URL] --> B{网页类型检测} B -->|静态页面| C[requests+BeautifulSoup解析] B -->|动态页面| D[Selenium渲染] C --> E[查找下载关键词/按钮] D --> E E --> F[智能识别下载链接] F --> G[模拟点击/下载APK] ``` --- #### **二、静态模式(requests+BeautifulSoup)** **适用场景**:APK链接直接存在于HTML源码中的静态页面[^1] 1. **解析URL与获取页面** ```python import requests from bs4 import BeautifulSoup url = "https://example.com/apk_download" headers = {'User-Agent': 'Mozilla/5.0'} # 避免反爬 response = requests.get(url, headers=headers) soup = BeautifulSoup(response.text, 'html.parser') ``` 2. **智能下载按钮识别策略** ```python # 策略1:关键词匹配(中英文+文件扩展名) keywords = ['下载', 'Download', 'APK', '.apk'] # 策略2:属性特征匹配 download_links = [] for a_tag in soup.find_all('a'): href = a_tag.get('href', '') text = a_tag.get_text().strip() # 检查关键词或.apk扩展名 if any(kw in text for kw in keywords) or href.endswith('.apk'): download_links.append(href) # 检查常见class/id(如.download-btn) if 'download' in a_tag.get('class', []) or 'download' in a_tag.get('id', ''): download_links.append(href) ``` 3. **文件下载** ```python for link in download_links: # 处理相对URL if not link.startswith('http'): link = requests.compat.urljoin(url, link) # 下载APK apk_response = requests.get(link, stream=True) with open('target.apk', 'wb') as f: for chunk in apk_response.iter_content(chunk_size=1024): if chunk: f.write(chunk) ``` --- #### **三、动态模式(Selenium)** **适用场景**:需交互触发下载的页面(如点击按钮后生成链接)[^2] 1. **初始化浏览器** ```python from selenium import webdriver from selenium.webdriver.common.by import By options = webdriver.ChromeOptions() options.add_argument('--headless') # 无头模式 driver = webdriver.Chrome(options=options) driver.get(url) ``` 2. **智能按钮识别与模拟点击** ```python # 策略:多层识别机制 button_selectors = [ "//a[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'download')]", # 文本匹配 "//button[contains(@class, 'download')]", # 类名匹配 "//*[@id='download-button']" # ID匹配 ] for selector in button_selectors: try: button = driver.find_element(By.XPATH, selector) button.click() break # 找到即触发 except: continue ``` 3. **获取动态生成的APK链接** ```python # 监听新出现的下载链接 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//a[contains(@href, '.apk')]")) ) apk_element = driver.find_element(By.XPATH, "//a[contains(@href, '.apk')]") apk_url = apk_element.get_attribute('href') # 通过requests下载(避免Selenium下载管理) import requests requests.get(apk_url) # 下载代码同上 ``` --- #### **四、智能策略优化** 1. **混合模式决策逻辑** ```python if "javascript" in soup.find_all('script'): # 检测JS动态内容 use_selenium = True else: use_selenium = False ``` 2. **反爬应对** - 随机User-Agent轮换 - Selenium添加 `--disable-blink-features=AutomationControlled` - 关键操作添加随机延迟:`time.sleep(random.uniform(1,3))` --- #### **五、典型问题解决方案** | 问题类型 | 解决方法 | |-------------------------|-----------------------------------| | 点击按钮后弹出新窗口 | `driver.switch_to.window(driver.window_handles[1])` | | 验证码拦截 | 集成第三方打码平台API | | 下载链接需登录 | Selenium自动填充表单+保存cookies | | 动态生成的临时下载链接 | 监听网络请求(如Selenium Wire) | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值