Python + Selenium:自动翻页爬取某图片网站指定图集

news/2024/5/21 7:09:37/文章来源:https://blog.csdn.net/qq_21264377/article/details/108159132

简单来说,爬取工作前期任务是了解目标网站的体系结构和“反爬策略”,然后是根据现有软硬件资源环境条件设计代码,反复迭代测试,最终实施部署。

之前,写过爬取图片网站的PHP和Python代码spi之类,通过读取HTML文本内容,模糊检索HTML img标签获取资源。批量爬取效率较高,但是只能应对“宽松”的爬虫应对策略,须应对各种不同文本编码和网站管理员的“疏忽”造成的编码混乱问题,且受网路网络实时状况影响较大,出现不稳定的现象。今昨心血来潮,改进原来的思路,采用Python + Selenium + 自定义HTML DOM解释器1(正则表达式RE)来实现。效率不如检索纯HTML文本高,但是准确率、稳定性较高。

先开展前期准备工作,深入了解目标体系结构。

任意点开一个目标图集网页:

2-1目标图集标题和翻页方式

可以看到图集的标题、更新时间、栏目以及翻页方式等等详细信息。由于需要自动翻页,获取图片页数的边界很重要。刚好,图集的页数总量在标题中。这样,只需获取该HTML节点的HTML文本(innerHTML),加以正则表达式就可以识别。完美解决翻页次数的问题。而翻页,如“温馨提示”所说 – “点击图片”即可。Selenium具有鼠标点击HTML节点操作的事件。

# 标题内容包含页码信息
pagePattern='([0-9]+[/][0-9]+)'
# 匹配标题HTML的页码
matches=re.findall(pagePattern, html)
# 目标只有一个
counts=matches[0]

现在通过浏览器来查看目标的HTML结构。博主使用的是Chrome浏览器(Firefox/Internet等Selenium支持的都可以)。右击目标图片检查:

2-2目标HTML体系结构

从图片看出,目标图片被包含在一个超链接,超链接被包含在一个div标签。目标的体系结构相对较简单。在网页加载进来,目标标签渲染完成后,定位该标签节点,获取其HTML文本内容,加以分析得出目标图片的地址。保存目标后,操作点击事件实现自动翻页,进行下一次处理分析,直到到达上述翻页界限。自动翻页结束后,开始下载上述步骤获取的目标图片集。

实现过程明确,开始实现设计代码。

# -*- coding: utf-8 -*-
#!/usr/bin/env python"""
@author: WowlNAN@github: https://github.com/WowlNAN@blog: https://blog.csdn.net/qq_21264377"""
"""
Get target pictures of specific website
"""import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECS
from htmldom import *
import re
import sys
from schedule import *class Solution:def __init__(self):self.url=''self.driver=webdriver.Chrome()self.images={}self.path=Nonedef __delete__(self):self.url=Noneself.images=Noneself.path=''if self.driver:self.driver.close()self.driver=Nonedef reset(self):self.url=''self.images={}self.path=Nonedef dictimage(self, index: int, url: str):if self.images.get(index, '')=='':self.images[index]=urldef pickimage(self, index: int, html: str):imagehtmls=match('//a//img', html)image=re.findall('src="([^<>"]*)"', imagehtmls[0])[0]self.dictimage(index, image)return imagedef getimages(self, url: str):if not url:return Noneelif not url.strip():return Noneelif not url.startswith('http://') and not url.startswith('https://'):return Noneself.path=url.split('/')[-1].split('.')[0]# 加载目标图集网页self.driver.get(url)# 设置等待事件wait=WebDriverWait(self.driver, 5)time.sleep(1)  # 指定等待事件内容:直到目标class元素出现          targetelement=wait.until(ECS.presence_of_element_located((By.CLASS_NAME, 'center')))#print('wait  ', url, end='')if not targetelement or targetelement==[]:return None# 获取根节点 -- 目标所在标签节点的HTML文本内容html=targetelement.get_attribute('innerHTML')if not html:return# 从根节点获取标题节点HTMLtitlehtml=match('//h1:class=center', html)if not titlehtml:return# 正则匹配页码信息counterhtml=re.findall('([0-9]+[/][0-9]+)', titlehtml[0])if not counterhtml:return counts=counterhtml[0].split('/')# 起止页码current=int(counts[0])end=int(counts[1])# 分析HTML获取目标图片self.pickimage(current, html)print('loading...', str(current)+'/'+str(end)+'    ', end='')time.sleep(1)i=current+1while i<end+1:try:# 操作点击目标节点事件targetelement.click()time.sleep(.5)# 指定等待事件内容:直到目标class元素出现 targetelement=wait.until(ECS.presence_of_element_located((By.CLASS_NAME, 'center')))      print('\rloading...', str(i)+'/'+str(end)+'    ', end='')if not targetelement or targetelement==[]:i+=1continue# 从根节点获取标题节点HTMLhtml=targetelement.get_attribute('innerHTML')# 分析HTML获取目标图片image=self.pickimage(i, html)i+=1except:i+=1# 开始下载目标图片集合# start downloadstime.sleep(1)codes={'hit':0, 'done':0, 'failed':0}i=1for key in self.images.keys():print('\rcaching...', str(i)+'/'+str(end)+'   ', end='')# 下载图片act=schedule.schedule(self.images.get(key), path=self.path)# 根据反馈信息,统计下载情况codes[act]=codes[act]+1i+=1time.sleep(.1)# 生成下载统计表格keys='|'actions='|'l=len(codes.keys())i=0for key in codes.keys():kl=16-len(key)keys+=' '*(kl//2)+key+' '*(kl-kl//2)al=16-len(str(codes[key]))actions+=' '*(al//2)+str(codes[key])+' '*(al-al//2)i+=1if i>0:keys+='|'actions+='|'print('\r|'+('-'*16+'|')*l, end='\n')print(keys)print('|'+('-'*16+'|')*l)print(actions)print('|'+('-'*16+'|')*l)print("ENTER:[eg, http://a.com/b/c.html]")
url=' '
while url:if url:s.getimages(url)time.sleep(.2)s.reset()# 命令行输入目标图集首页地址(可跳页)url=input(">>")       

schedule.py

# -*- coding: utf-8 -*-
#!/usr/bin/env python"""
@author: WowlNAN@github: https://github.com/WowlNAN@blog: https://blog.csdn.net/qq_21264377"""import requests
import ssl
import socket
from fio import fio
import os
import time
import datetimeclass Schedule:def __init__(self):passdef schedule(self, url, path=None, delay=.1):            if url==None or url.strip()=='':return 'failed'else:# wait until delay is overtime.sleep(delay)count=1completed=Falsewhile count<=3 and not completed:                    try:# http headersheaders={'User-Agent':'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:64.0) Gecko/201001003 Firefox/64.0','Referer':url,'authority':'www.ttbcdn.com','method':'GET','scheme':'https','accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8','accept-encoding':'gzip, deflate, br','accept-language':'zh-CN,zh;q=0.8','cache-control':'max-age=0','upgrade-insecure-requests':'1'}# create directories according to date and the relative pathcurrenttime=datetime.datetime.now()                    tmpdir=fio.getTempDir()+'/'+currenttime.strftime("%Y")+'/'+currenttime.strftime("%m")+'/'+currenttime.strftime("%d");paths=url.split('/')# check if the specific storage path is setif not path:                        tmpdir+='/'+paths[-2]else:tmpdir+='/'+pathfio.mkdirs(tmpdir)tmpfilename=tmpdir+'/'+paths[-1]if os.path.exists(tmpfilename):# repeat downloadreturn 'hit'else:# download is readyssl._create_default_https_context=ssl._create_default_https_context=ssl._create_unverified_contextsocket.setdefaulttimeout(5)#req = request.Request(url, headers=headers)#response = request.urlopen(req)'''opener=request.build_opener()opener.addheaders=[('User-Agent', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0'), ('Referer', task.getreferer())]response=request.urlretrieve(url, tmpfilename, self.joblistener)'''#The following step with referer:response=requests.get(url, headers=headers, timeout=5)#if response.getcode()==200:#con = response.read()if response.status_code==200:f=open(tmpfilename, 'wb')for con in response.iter_content(chunk_size=512):if con:f.write(con)f.close()completed=True#print('\rdone  ', url, end='')return 'done'else:# retry after problemscount+=1                            except :#Exception as err:# retry after exceptioncount+=1if not completed:# download failedreturn 'failed'# Run under process instead of thread                       schedule=Schedule()            

首次下载效果图:

首次下载效果图2-1

重复下载效果图:

重复下载效果图2-2

首次下载得到8张图片 – “done”。重复下载后,提示包含8个重复目标 – “hit”。(下载失败 – “failed” 略)

保存至本地文件2-1
保存至本地文件2-2

2020-08-22 01:21PM Sat.

关于PhantomJS:

PhantomJS满天飞而Chrome之流还没有headless的时候,尝试PhantomJS 基于webkit的headless浏览器,结果发现一些“严格”反爬虫机制的网站反馈“浏览器版本过低”。看到Selenium.dev介绍,PhantomJS基于比较旧、远低于Chrome和safari浏览器的webkit版本,该项目已自2017年8月5日停止维护。而在此之前Chrome维护方Google宣布推出开发者headless版本。
PhantomJS项目停止维护

2020/10/27 Tues.

以上可以描述为“逻辑计数器”方式(Logical Counter)。另一种简单的翻页方式:自然语言特征(Natural Language Feature)。也就是说,通过自然语言来描述翻页方式,指定翻页的途径。比如说,中文的“下一页”,英文的“Next”等等。这种方式比较直观清晰。一般情况下,其目标很轻松就能在简洁的代码中得以实现。
很多时候,此类网站的HTML代码类似于:<a href="a.com/b?page=2">下一页</a>或者<a href="a.com/b?page=2">Next</a>。据此,可以通过查找包含类似自然语言特征码的a超链接标签,得知下一页的位置是否存在以及内容。使用Python + Selenium可以使用以下代码:

import traceback
from selenium import webdriver
from selenium.webdriver.common import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECS
...
try:clickelement=wait.until(ECS.presence_of_element_located((By.PARTIAL_LINK_TEXT, 'Next')))
except:try:clickelement=wait.until(ECS.presence_of_element_located((By.PARTIAL_LINK_TEXT, '下一页')))if clickelement:# Chinese中文语言特征,按照目标区域语言调整。chn=Trueexcept:traceback.print_exc()
...
pageend=True
if clickelement:# 判定页面集合的终点,这里以超链接地址为“#”或以“#”号结尾的地址pageend=clickelement.get_attribute('href')=='#' or clickelement.get_attribute('href').endswith('#')while clickelement and not pageend:# Do somethingtry:...finally:try:# Chinese中文语言特征码if chn:clickelement=wait.until(ECS.presence_of_element_located((By.PARTIAL_LINK_TEXT, '下一页')))else:# English英文语言特征码clickelement=wait.until(ECS.presence_of_element_located((By.PARTIAL_LINK_TEXT, 'Next')))# 重新判定页面集合的终点if clickelement:pageend=clickelement.get_attribute('href')=='#' or clickelement.get_attribute('href').endswith('#')except:# 出现错误判定翻页动作结束pageend=Truetraceback.print_exc()

自然语言特征码和逻辑计数器两种方式,各有优缺点。自然语言特征码直观简洁,通用性广;逻辑计数器针对性强,效率表现良好。凡事具有两面性,不能一概而论。互联网环境因人而异,网络生态环境复杂多变(Complex)。因此,需要灵活多变的应对策略。


  1. 自定义HTML DOM解析器,来源于之前写的HTML标签选择器的系列文章。 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_794510.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python + Selenium: 爬取某社交门户网站新闻栏目焦点

以前通过直接获取的HTML文本内容分析过&#xff0c;但是明显毫无结果。彼时深切体会到要想测试爬取“普通”反爬虫策略级别以上的网站内容&#xff0c;必须从浏览器内核级别入手。因为只有彻底模拟浏览器的行为&#xff0c;才无法被机器人100%识别为爬虫而遭到限制或拒绝服务。…

多层次应对HTTPS网站超时:selenium.common.exceptions.TimeoutException

现在网络越来越普及&#xff0c;带宽速度普遍也有较大提升。伴随网络的普及&#xff0c;同时快速增长的还有网民的数量和网络流量。网站超时响应的“通病”&#xff0c;仍然是无法完全避免的。尤其是在网络流量高峰期访问HTTPS网站&#xff0c;使用类似Selenium的浏览器内核驱动…

阿里云轻量服务器部署PHP网站(基于Lamp)

一&#xff1a;首先登陆阿里云账户购买轻量服务器&#xff08;这里就不详细介绍啦&#xff09;【轻量服务器会提供PHP,Apache,Mysql,不需要我们自己安装&#xff0c;方便很多】 如果是选择阿里云ecs服务器的话可以参考&#xff1a;https://blog.csdn.net/qiaosym/article/deta…

[转载]使用IntelliJ IDEA开发SpringMVC网站(一)开发环境

访问GitHub下载最新源码&#xff1a;https://github.com/gaussic/Sp... 文章已针对IDEA 2016做了一定的更新&#xff0c;部分更新较为重要&#xff0c;请重新阅读文章并下载最新源码。另外&#xff1a;文中的附图部分仍然为旧版本&#xff0c;请参照自身版本进行配置。 前言 由…

ASP.NET 2.0中轻松实现网站换肤

&#xff1a; 查看个人网站 查看详细资料 &#xff1c;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&#xff1e; &#xff1c;html xmlns"http://www.w3.org/1999/xh…

JQuery 的跨域方法 可跨任意网站

因发现有不少博友发园内短信问及JS的跨域问题&#xff0c;我想很多程序员的脑海里面还认为JS是不能跨域的&#xff0c;其实这是一个错误的观点&#xff1b;有很多人在网上找其解决方法&#xff0c;教其用IFRAME去解决的文章很多&#xff0c;真有那么复杂吗&#xff1f;其实很简…

推荐一个可以往blog里面加入旅行线路图的travel map网站

今天无意中发现这个网站&#xff0c;Free Travel Map Widget&#xff0c;可以很方便的做一个travel map&#xff0c;然后生成html代码放到blog里面。效果可以看看我之前的泰国和欧洲的blog更新&#xff0c;加了map。转载于:https://www.cnblogs.com/fresky/archive/2010/11/03/…

高性能网站建设之减少Http连接数

关于CSS背景图合并工具&#xff0c;请大家参看随笔&#xff1a;Css背景图合并工具功能增强&#xff08;V0.1&#xff09; 在对大访问量网站进行性能优化时&#xff0c;其中有一点是尽量减少http连接数&#xff0c;道理很明了&#xff0c;减少了单个PV的http连接数&#xff0c;…

通过脚本方式导出SharePoint网站集用户及其角色列表

这是课堂上的一个例子&#xff0c;分享出来给大家参考用。如果你管理一个或者多个网站集&#xff0c;那么这个脚本将有助于你快速地了解用户信息。 管理员们&#xff0c;懂点脚本还是很有用的哦&#xff0c;呵呵 将下面的脚本保存为一个ps1文件function Get-UsersWebPermission…

php与mysql网站开发..._Mysql 与 php动态网站开发 入门教程,mysql网站开发_PHP教程...

Mysql 与 php动态网站开发 入门教程&#xff0c;mysql网站开发这个系列的教程由表单开始写&#xff0c;因为表单可以把数据库和web 之间的交互表现得很明显。提交表单 &#xff0c;数据库记录注册信息。本教程属于基础教程。大神请略过。对于php和mysql之间的稳固性很受程序员的…

linode服务器登录网站,linode 服务器

linode 服务器 内容精选换一换云服务器组是对云服务器的一种逻辑划分&#xff0c;云服务器组中的弹性云服务器遵从同一策略。当前仅支持反亲和性&#xff0c;即同一云服务器组中的弹性云服务器分散地创建在不同的主机上&#xff0c;提高业务的可靠性。您可以使用云服务器组将业…

黑人抬棺html网站源码

黑人抬棺html源码 成品地址&#xff1a;https://www.52fenxiang.top/hrtg/ 源码下载地址&#xff1a;https://www.52fenxiang.top/thread-448-1-1.html

用DIV+CSS的网页布局对SEO的好处

为什么80%的码农都做不了架构师&#xff1f;>>> DIVCSS是网站标准&#xff08;或称“WEB标准”&#xff09;中常用术语之一&#xff0c;通常为了说明与HTML网页设计语言中的表格&#xff08;table&#xff09;定位方式的区别&#xff0c;因为XHTML网站设计标准中&a…

最新70佳单页网站设计案例欣赏(下篇)

单页网站是指只有一个页面的网站&#xff0c;这种形式的网站曾经非常流行&#xff0c;现在依然有很多人喜欢。不过&#xff0c;并不是每个网站都适合做成单页&#xff0c;一般都是内容比较少而且将来内容也不怎么增加的情况才适合这样做。如果你打算做一个这样的网站&#xff0…

在线压缩图片网站源码

今天分享给小伙伴一份在线压缩图片的网站源码&#xff0c;也算是比较实用的一份源码&#xff0c;测试地址我会贴在【效果展示】段落下面&#xff0c;喜欢的小伙伴自行下载吧。 #效果展示 效果展示&#xff1a;图片在线压缩效果展示 来自&#xff1a;12580code源码站

表白网站源码-html源码

#源码介绍 一份表白网站源码&#xff0c;里面用到的一些小技巧还是可以学习的&#xff0c;需要用的的小伙伴可以拿去用哈&#xff0c;下载完成后打开index.html&#xff0c;然后修改文本和修改图片就可以啦&#xff0c;小二在这祝你们成功哦&#xff08;哈哈哈哈哈哈&#xff0…

对SEO优化有一定作用的DIV+CSS命名规则

为什么80%的码农都做不了架构师&#xff1f;>>> SEO(搜索引擎优化)有很多工作要做&#xff0c;其中对代码的优化是一个很关键的步骤。为了更加符合SEO的规范&#xff0c;下面中部IT网将对目前流行的CSSDIV的命名规则整理如下&#xff1a; 页头:header 登录条:login…

CJC(一): ToStringBuilder两种方法用法优缺点及一个问题 - rmn190 - ITeye技术网站

CJC(一): ToStringBuilder两种方法用法优缺点及一个问题 - rmn190 - ITeye技术网站CJC(一): ToStringBuilder两种方法用法优缺点及一个问题 博客分类&#xff1a;Source Codes Study设计模式F#Security CJC是Common Java Cookbook的缩写, 这是一本介绍ApacheCommon开源项目的电…

大型网站架构演变的知识体系

之前也有一些介绍大型网站架构演变的文章&#xff0c;例如LiveJournal的、ebay的&#xff0c;都是非常值得参考的&#xff0c;不过感觉他们讲的更多的是每次演变的结果&#xff0c;而没有很详细的讲为什么需要做这样的演变&#xff0c;再加上近来感觉有不少同学都很难明白为什么…

大流量网站的底层系统架构

为什么80%的码农都做不了架构师&#xff1f;>>> 动态应用&#xff0c;是相对于网站静态内容而言&#xff0c; 是指以c/c、php、Java、perl、.net等 服务器端语言开发的网络应用软件&#xff0c;比如论坛、网络相册、交友、BLOG等常见应用。动态应用系统通 常与数据…