码前冷静分析

首先需要准备好selenium、requests库以及Chromedriver

  • 这个就不细说了,有很多博客可以参考

然后讲一下大体思路

首先搜索想要爬取图片的关键词

- 接着是“搜集”搜索结果

- 然后想办法逐一进入搜索结果,进而获取内容

- 最后就是下载了

框架大体如下

框架是个大体思路(草稿),写代码的时候可以灵活来

def get_list(url): #目的是根据关键词搜索,抓取每一条结果的图片链接
	lst = []
	browser = webdriver.Chrome()
	wait = ww(browser, 10)
	#……等等等等
	return lst
	
#胡乱摸索了线程简单的应用,就copy了另一个一样的下载函数
def download_pic1(lst): #逐一遍历列表中的图片链接,下载美图
	return ''

def download_pic2(lst): #逐一遍历列表中的图片链接,下载美图
	return ''
	
def main(): 
	global keyword
	keyword = '鬼刀'
    basic_url = 'https://www.toutiao.com/'
    lst = get_list(basic_url) #访问主页,搜索,收集结果的图片链接,返回列表
    download_pic(lst) #根据链接下载图片
    #就是这么小白式的简单粗暴,水平还不够,暂时就只弄两个函数吧
    #虽然是有点臃肿了,嘤嘤嘤
  • 先声明下,本人是个小白,可能思路,代码存在一些个问题
  • 这里还请大家多多指教

完整代码在文末

开 码

首先把要用的库给喊粗来

库,函数的使用介绍有很多超棒的博客,本文会给出部分链接
  • 好的,上代码
import requests
from time import sleep
import os
import os.path as op
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait as ww
import threading

1.1 访问今日头条首页,关键词传送及点击搜索

def get_list(basic_url):
    lst = []
    browser = webdriver.Chrome()
    wait = ww(browser, 10)
    try:
        browser.get(basic_url)
        #找到搜索框节点
        input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#rightModule > div.search-wrapper > div > div > div > input')))
        #找到搜索按钮节点
        click = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#rightModule > div.search-wrapper > div > div > div > div > button')))
        input.send_keys(keyword) #模拟传入搜索词
        sleep(2)  #输入后停一下,要不然立马让你验证,来自小白的喵喵喵
        click.click()  #模拟点击搜索按钮
    except Exception as er:
    	print(er)

# 两个节点的查找看下图

节点查找~超详细解答如下博文

博主 Eastmount 原创
【[python爬虫] Selenium常见元素定位方法和操作的学习介绍】

wait用法详解~如下链接

博主 不码不成才 原创
【python+selenium中的wait事件】

CSS选择器用法介绍~博文链接如下

博主 MXuDong 原创
CSS选择器——cssSelector定位方式详解

到主页后右键—>检查—>开找
- 首先是输入框查找(按照图示顺序很快就找到啦)
- 然后右键点击节点,copy—>copy selector
啦啦啦~

python selenium无头模式 python 无头浏览器多线程_Python


python selenium无头模式 python 无头浏览器多线程_python selenium无头模式_02

接下来同样找到搜索按扭
同样的操作,只是要注意复制对节点信息哦
|

python selenium无头模式 python 无头浏览器多线程_requests_03

节点查找~超详细解答如下博文

博主 Eastmount 原创
【[python爬虫] Selenium常见元素定位方法和操作的学习介绍】

wait用法详解~如下链接

博主 不码不成才 原创
【python+selenium中的wait事件】

CSS选择器用法介绍~博文链接如下

博主 MXuDong 原创
CSS选择器——cssSelector定位方式详解

这样就进入到了搜索结果界面,接下来就是让它加载出更多结果,通过模拟滑动来实现

1.2 接下来便是模拟滑动页面,出加载更多结果,上码

# 首先把browser切换到当前搜索结果的页面
browser.switch_to.window(browser.window_handles[1])
#滑动多少自己可以任意发挥
for i in range(0, 2001, 250):
	#下边这个方法来模拟滚动屏幕(详解可以参考其它博客)
    browser.execute_script(f'window.scrollBy(0, {i})')
    sleep(2)
#滑的差不多了,您是不是该寻思着收集进入结果的''门''了?
clicks = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.link.title')))

模拟滑动所用的方法【execute_script()】相关博客链接如下。

【博主 吾爱乐享 原创-----python学习之滚动页面函数execute_script】 +
【博主 qq_16069927 原创 ----selenium 如何控制滚动条逐步滚动】

  • 来一起找这’'门’‘吧!

    经过观察以及实践,点击标题链接可以进子入页面,就是你了皮卡丘!(就是蓝色阴影那个节点)
  • 首先观察,class有两个属性,所以CSS选择器因该是 ‘.link.title’,既然找到了,就都收集起来吧,哈哈

1.3 接下来,就开始邪恶的循环,打开子页面->回到搜索结果页->打开子页面->回到搜索结果页……

  • 别问为什么,问就是网速慢,先打开页面,让成熟的它自己加载着,然后挨个收割美图链接
  • 不要问为什么不找到链接当时就给图片给下了,问就是缺少仪式感。
上码!
for clc in clicks[1:10]:  # 搜索结果打开数自己定,我是因为穷,惨,所以就10个吧(嘤嘤嘤)
	clc.click()
	#进入子页面后,趁它不注意,赶快回到结果页
	browser.switch_to.window(browser.window_handles[1])
sleep(4)

1.4 然后开始收割美图链接吧,哈哈!

上码!
for num in range(len(browser.window_handles) - 2):
	#逐个进入子页面
	browser.switch_to.window(browser.window_handles[num + 2])
	#等待所有图片节点加载粗来,收集它
	try: #可能会遇到视频界面,到时候这里判断错误就不管,进入下一个
		img = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[src]')))
	except:
		pass
	#提取链接到列表
	for mg in img:
    	url = mg.get_attribute('src')
    	if url.startswith('http://p') and 'thumb' not in url:
        	lst.append(url)

老问题,找节点,上图!!!

通过分析,可以看出,文章中图片链接都在图中红线标注的 ‘路径’内,所以……

python selenium无头模式 python 无头浏览器多线程_Python_04

可以构造一个CSS选择器,筛选出所有含图链接节点 ,通过实战,发现有两种页面:
常见的一种是一页到底那种,图片在-> ‘.article-content div .pgc-img img[src]’,
另一种是跟ins一样左右切换那种
两种页面图片节点路径就不一样了,但是标签名都是<img>属性都是’src’,所以选择器就粗糙一点"img[src]"
这样就需要筛选一下了,粗糙的选择器就会获取到一些广告图,实战发现,广告图链接几乎都是’https://……”而图片链接是“http://……”这就很妙了,如代码

【这里很粗糙,还是可能会爬到不相关的,flag:以后有时间再改进改进】

2.接下来就是下载了!

这里我后来翻了一些优秀博客,胡乱摸索,写了个very简单(因为菜)的双线程下载
说白了就是同时运行两个下载函数,男人嘛,不能叫快要叫效率
上码
def download_pic1():
	#单独搞个文件夹存一下
    path = r'C:\Users\PXO\Desktop\杂\Toutiao_pic\\' + keyword
    if not op.exists(path):
        os.mkdir(path)
    ln = len(lst)
    id = [i for i in range(ln)]
    cnt = 1
    for url in lst[:ln//2]:#负责前半部分列表下载
    	#开始搞事情,遍历图片链接,get get get!
        r = requests.get(url)
        #这里设置文件保存路径(含文件名)
        pic_path = path + '\\' + f'{keyword}_pic_{id.pop(0)}.jpg'
        #以二进制写入方式打开命名好的文件
        with open(pic_path, 'wb+') as ff:
        	#写入获取到的图片(二进制)//养成好习惯,随手关闭
            ff.write(r.content)
            ff.close()
        #下边是一个小优化,刷新显示当前下载状态
        op1 = cnt*120//ln
        en = 60 - op1
        opp, enn = '-'*op1, '*'*en
        print(f'\r[1]下载ing:已下{cnt}/{ln//2}张,[{opp}>{enn}] {(2 * cnt) / len(lst):.1%}', end='')
        cnt += 1
#下边copy一下就是另一个啦
def download_pic2():
    path = r'C:\Users\PXO\Desktop\杂\Toutiao_pic\\' + keyword
    if not op.exists(path):
        os.mkdir(path)
    ln = len(lst)
    id = [i for i in range(ln)]
    id.reverse()
    cnt = 1
    for url in lst[ln//2:]:#负责下载后半部分
        r = requests.get(url)
        pic_path = path + '\\' + f'{keyword}_pic_{id.pop(0)}.jpg'
        with open(pic_path, 'wb+') as ff:
            ff.write(r.content)
            ff.close()
        op1 = cnt*120//ln
        en = 60 - op1
        opp, enn = '-'*op1, '*'*en
        print(f'\r[2]下载ing:已下{cnt}/{ln//2}张,[{opp}>{enn}] {(2 * cnt) / len(lst):.1%}', end='')
        cnt += 1
小说明:这里就不传参数了,直接把列表定义为全局变量

线程的代码,还有博客参考如下

#大家可以参考下面给出的优秀博客
    threads = []
    th1 = threading.Thread(target=download_pic1)
    threads.append(th1)
    th2 = threading.Thread(target=download_pic2)
    threads.append(th2)
    for th in threads:
        th.setDaemon(True)
        th.start()
    th.join()
参考博客链接
[博主 n_laomomo 原创]----Python多线程threading用法
较详细介绍
【博主 DrStream 原创】----python:threading.Thread类的使用详解

奉上完整代码

  • 注意:爬取的时候会出现超时,然后就over了,除了使用try来’试错‘,还可以适当用一下time库的sleep()
import requests
from time import sleep
import os
import os.path as op
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait as ww
import threading

def get_list(basic_url):
    '''
	#这里是无界面浏览器相关操作,不想要弹出界面的话,
	#把下边那行换成这些就ok
    browser_options = webdriver.ChromeOptions()
    browser_options.add_argument('--headless')
    browser = webdriver.Chrome(options=browser_options)
    '''
    browser = webdriver.Chrome()  #这行就是那行(手动滑稽)
    wait = ww(browser, 20)
    try:
        browser.get(basic_url)
        print('访问成功!!')
        sleep(1)
        input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#rightModule > div.search-wrapper > div > div > div > input')))
        click = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#rightModule > div.search-wrapper > div > div > div > div > button')))
        input.send_keys(keyword)
        sleep(2)
        click.click()
        sleep(1)
        print('搜索成功!')
        browser.switch_to.window(browser.window_handles[1])
        for i in range(0, 2001, 250):
            browser.execute_script(f'window.scrollBy(0, {i})')
            print(f'\r加载中。。。{i/2000:.1%}', end='')
            sleep(3)
        print('')
        clicks = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.link.title')))
        cnt = 0
        want = 10  ## 爬取页面数 
        for clc in clicks[: want]:  
            clc.click()
            sleep(2)
            cnt += 1
            browser.switch_to.window(browser.window_handles[1])
            print(f'\r已打开{cnt}个界面,比例{cnt/want:.2%}', end='')
        print()
        for num in range(want):
            browser.switch_to.window(browser.window_handles[num + 2])
            try:
                img = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'img[src]'))) #.article-content div .pgc-img img[src]
            except:
                pass
            for mg in img:
                url = mg.get_attribute('src')
                if url.startswith('http://p'):
                    lst.append(url)
    except Exception as t:
        print(t)
def download_pic1():
    path = r'C:\Users\PXO\Desktop\杂\Toutiao_pic\\' + keyword
    if not op.exists(path):
        os.mkdir(path)
    ln = len(lst)
    id = [i for i in range(ln)]
    cnt = 1
    for url in lst[:ln//2]:
        r = requests.get(url)
        pic_path = path + '\\' + f'{keyword}_pic_{id.pop(0)}.jpg'
        with open(pic_path, 'wb+') as ff:
            ff.write(r.content)
            ff.close()
        op1 = cnt*120//ln
        en = 60 - op1
        opp, enn = '-'*op1, '*'*en
        print(f'\r[1]下载ing:已下{cnt}/{ln//2}张,[{opp}>{enn}] {(2 * cnt) / len(lst):.1%}', end='')
        cnt += 1
def download_pic2():
    path = r'C:\Users\PXO\Desktop\杂\Toutiao_pic\\' + keyword
    if not op.exists(path):
        os.mkdir(path)
    ln = len(lst)
    id = [i for i in range(ln)]
    id.reverse()
    cnt = 1
    for url in lst[ln//2:]:
        r = requests.get(url)
        pic_path=path+'\\'+f'{keyword}_pic_{id.pop(0)}.jpg'
        with open(pic_path, 'wb+') as ff:
            ff.write(r.content)
            ff.close()
        op1 = cnt*120//ln
        en = 60 - op1
        opp, enn = '-'*op1, '*'*en
        print(f'\r[2]下载ing:已下{cnt}/{ln//2}张,[{opp}>{enn}] {(2 * cnt) / len(lst):.1%}', end='')
        cnt += 1
def main():
    global keyword, lst
    lst = []
    keyword = '鬼刀' 
    basic_url = 'https://www.toutiao.com/'
    get_list(basic_url)
    threads = []
    th1=threading.Thread(target=download_pic1)
    threads.append(th1)
    th2=threading.Thread(target=download_pic2)
    threads.append(th2)
    for th in threads:
        th.setDaemon(True)
        th.start()
    th.join()

main()

python selenium无头模式 python 无头浏览器多线程_python selenium无头模式_05