selenium 查找页面某元素是否存在 pythhon_使用selenium+多线程爬某宝,全是骚操作(仅供学习)...

v2-6e4b697c3e0b2a4cc0c49c52dad7a6e5_1440w.jpg?source=172ae18b
v2-79ddc7c195ad9335265f57f1148351e5.jpg
https://www.zhihu.com/video/1107799335122751488

v2-bec030fb7fd24a184f8af44c6afd9726_b.jpg

1.起

在写上了上次的selenium模拟登录淘宝后,本来是想先写个ip池的教程的,但是在爬某宝的时候发现,ip池的作用不大,也可能是代理ip的质量不够高造成的。不过就算在没使用代理ip的情况一下,还是把某猫的nike专卖店男士的全部分类爬了下来。


2.承

在模拟登录了某宝之后使用就可以使用selenium的函数来寻找页面中的元素了,于是我们打使用这些函数,在搜索框中搜索nike,出现如下页面

v2-b0acc37f63ea2f274dd6cc7edbef4ce6_b.jpg

这是只要点击这张图,就可以进入到某猫的nike专卖店了,这是要特别注意的是,这张图是一个iframe,我们知道selenium如果想要要查找到iframe中的元素,是需要切换到这iframe里的,但是这里我直接把iframe当节点找,然后点击即可。

v2-b1c83d892f1864a2b1dafb7c1cc9658f_b.jpg

进去之后找到男子节点,点击跳转页面,这里不多说。到这里为止,把执行这部分操作的叫做openPage(browser)函数

代码如下,代码自行换行

def 

我们要根据打开页面的这一部分进行爬虫

v2-a6861c4688dddcd207a1c51485a18912_b.jpg

我们现在来找一下这一部分的在html中的结构是怎么样的,然后就可以通过selenium来操作他们

v2-3eda09761d59d9b6ddbb91ed7358276a_b.jpg

左边的所有鞋类,休闲鞋/拖鞋就存在右边<dd>..</dd>节点中,那么整齐的排列我们可以用xpath来找到他们,然后加入一个参数就可以一个个单独使用了。接下来骚的地方来了,正当你想用selenium试一下能不能一个个点开的时候,问题就来了。这是什么鬼东西啊??orz

v2-e90d672f232b73b922404224fc55fc0f_b.png

其实他的意思就是,你点击页面的操作被其他的元素收了。没错这是某宝做的反爬机制,一旦你对一个页面的点击超过三次就会出现这个。这时候我想既然selenium的点击操作被限制了次数,没事我还可以配合js脚本,用js去模拟点击就好这样。方法就是用selenium找节点位置然后使用下面的函数即可。但是要注意的是js点击这个东西有点玄乎,我测试的时候用selenium能的函数能点到的,js不一定能点到,然后只有填更详细的节点位置能点到。这里找位置使用xpath和css都随便,只要改变下面dd后面跟的数字就可以打开不同的分类。打开不同分类的函数我叫做他nextClass函数

d=wait.until(EC.element_to_be_clickable((By.XPATH,'//div[@class="J_TWidget nav180"]//dd[1]/a')))
browser.execute_script("(arguments[0]).click()",d)

在点击开分类以后会得到如下页面,要注意的是此时我们是打开了一个新的选显卡,出现的页面,也就是说窗口的句柄还是之前的,我们要切换过来,找元素的时候才能找得到。

v2-fb26a380a4de35620591c25f294a3df6_b.jpg

如果中可以见,在<div class="J_TItems" 下有很多个小div。这里的小div就是每一行的商品。每一行有四个商品,所以这个小div小还会有四个小小div,这就代表每一个商品。我们只需要重新找到节点,然后使用如上的js点击方法一个个点开就行了。不过要注意的都是每次点开都是一个新的选显卡记得切换窗口拿到当前句柄。然后在商品页你就可以为所欲为的使用解析库找自己想要的元素了,我这里找了鞋子型号、月销量、原价、销售价。这个函数我叫做getGoods。

然后是翻页函数,找完商品以后就看看能否翻页,能翻页的话继续找商品,不能翻页就找下一类了,翻页函数我叫做nextPage


3.转

接下来就是最关键的东西了,淘宝的验证怎么办?

v2-0840511f491271bcd10f071414f6800a_b.jpg

既然现在可以使用selenium了那可不可以使用其中的动作链呢,当然是不可以了,这个验证框也是个iframe,然后这个验证框的所有元素都是在iframe下的一个叫做#document的东西里,图中有显示!

=-=zzz 这还怎么爬啊.......没事还记得我们的pyautogui吗在上一篇的模拟登录有提到。因为这个窗口出现的位置永远都是一样的,因此我们只要计算好坐标就可以模拟鼠标操作去验证了。而只需要使用selenium中找元素的函数我们就能知道这个窗口是否出现了,出现了我们就调用pyautiogui去解决。

可问题又来了,我们怎么知道它什么时候出现,我必须有个函数可以时时检测才行啊,没错这就要使用到多线程了,我把这个检测函数叫做check,在程序开始后给check分配一个线程,然后他时时去检测有没有验证页面就可以了。代码如下checkAciton 就是模仿鼠标操作。切记使用异常处理多注意,有时候try中的代码出问题了,except有没有提示的话,是很难找到问题的

def check(browser):  #把这个函数弄成多线程函数然后挂起它,
    mutex = threading.Lock() #加锁
    wait=wdw(browser,5)#验证模块少等一点,而寻找模块等久一点,防止出现验证模块的时候切换到了寻找模块
    while True:
        mutex.acquire()
        print('执行一次')
        try:
            wait.until(EC.presence_of_element_located((By.XPATH,'//div[@id="J_sufei"]')))
            print('验证成功')
            checkAction()
            browser.refresh() #验证成功要刷新一次才能获取页面
            handle=browser.current_window_handle
            browser.switch_to_window(handle)
            time.sleep(30) #每次验证了等到久一点值再次去操作,要不然又会被检测,最后就算移动了也会失败
        except:
            print('没有检测到模块')
        mutex.release()

v2-548f97926a8b9ebaafe40f3028eaa83b_b.jpg

执行的时候,会在主线程与检测模块之间来回切换,至于操作系统是怎么调度的我就不知道了。

4.合

源代码如下

from selenium import webdriver as wb
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait as wdw
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import pyautogui
import threading
global browser


def switchWindows(browser,i):
    browser.switch_to_window(browser.window_handles[i])

def __login__(username,password,pathA,pathB):

    pyautogui.PAUSE=0.5  #设置每个动作0.2s太快来不及输入密码
    options=wb.ChromeOptions()
    options.add_experimental_option('excludeSwitches', ['enable-automation'])#切换到开发者模式
    browser=wb.Chrome(options=options)
    browser.maximize_window()  #窗口最大化保证坐标正确
    browser.get('https://login.taobao.com/member/login.jhtml')
#try:
    #left,top,width,height=pyautogui.locateOnScreen('G:/jupyter project/淘宝/login_switch_blue.PNG')
#except:
    #left,top,width,height=pyautogui.locateOnScreen('G:/jupyter project/淘宝/login_switch.PNG')      获取login_switch位置
    time.sleep(3)
    moveToX=1484
    moveToY=297
    pyautogui.moveTo(1484,297)  #移动到切换登录的位置
    pyautogui.click()  #点击切换按钮
    pyautogui.typewrite(username)
    pyautogui.press('tab')
    pyautogui.typewrite(password)
    errorType=0
    try:
        left,top,width,height=pyautogui.locateOnScreen(pathA)
        print('识别蓝色')
        moveToX=left+140
        moveToY=top+15
        print(moveToX,moveToY)
        pyautogui.moveTo(moveToX,moveToY)
        pyautogui.mouseDown()
        moveToX=moveToX+300
        pyautogui.moveTo(moveToX,moveToY)
        pyautogui.mouseUp()
        pyautogui.moveTo(moveToX-250,moveToY+60)
        pyautogui.mouseDown()
        pyautogui.mouseUp()
    except:
        errorType=1  #识别不出蓝色
        
    if errorType==1:
        try:
            left,top,width,height=pyautogui.locateOnScreen(pathB)
            moveToX=left+200
            moveToY=top+20
            print('识别红色')
            print(moveToX,moveToY) #1299 497
            pyautogui.moveTo(moveToX,moveToY)
            pyautogui.mouseDown()
            moveToX=moveToX+300
            pyautogui.moveTo(moveToX,moveToY)
            pyautogui.mouseUp()
            pyautogui.moveTo(moveToX-250,moveToY+60)
            pyautogui.mouseDown()
            pyautogui.mouseUp()
        except:
            errorTye=2  #识别不出绿色
            
    if errorType==2:
        print('没有滑块')
        pyautogui.moveTo(1189,497)
        pyautogui.mouseDown()
        pyautogui.mouseUp()
    #调整到淘宝首页
    
    wait=wdw(browser,10)
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'a[href="//www.taobao.com/"]'))).click()
    
        
    return browser  #返回浏览器当前的页面



def openPage(browser):#打开nike
    
    wait=wdw(browser,10)
    wait.until(EC.presence_of_element_located((By.ID,'q'))).send_keys('nike')
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.btn-search'))).click()
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'iframe[class="srp-iframe"]'))).click() #打开新窗口
    #browser.execute_script("(arguments[0]).click()",a)   淘宝启用了noscrpit反爬
    switchWindows(browser,1)  #切换窗口
  
    #打开女子,打开女子就验证
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'a[href="//nike.tmall.com/category-1394890745.htm?spm=a1z10.5-b-s.w4011-14234872789.54.4b40295bxWLzrN&search=y&scene=taobao_shop#TmshopSrchNav"]'))).click()
    #wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'a[href="//nike.tmall.com/category-1394899096.htm?spm=a1z10.5-b-s.w4011-14234872789.90.5694295bEoa4Mm&search=y&scene=taobao_shop#TmshopSrchNav"]'))).click()
    #browser.refresh()
    #wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'a[href="//nike.tmall.com/category-1394899099.htm?spm=a1z10.5-b-s.w4011-14234872789.70.2e8a295bMdIyvv&search=y&scene=taobao_shop#TmshopSrchNav"]'))).click()
    return browser

def nextClass(browser,page):
    
    wait=wdw(browser,10)
    name=str(page)
    tryTime=0
    while tryTime<10:  #如果点击失败了,就再试一次,四次都不成功就退出
        #time.sleep(5) 
        try:
            a=wait.until(EC.element_to_be_clickable((By.XPATH,'//div[@class="J_TWidget nav180"]//dd['+name+']/a')))#分类
            print(a.text)
            browser.execute_script("(arguments[0]).click()",a) #用脚本点击不用刷新
            switchWindows(browser,2)#现在一共有三个窗口切换过去
            print(browser)
            return browser #打开完以后就返回
        except:
                wait.until(EC.presence_of_element_located((By.XPATH,'//div[@id="J_sufei"]')))
                tryTime=tryTime+1 
                print('原来是检测了不要刷新,在循环一次试试')

    

def getGoods(browser):
    time.sleep(3)
    wait=wdw(browser,10)
    for row in range(1,11):  #商品一个最多多少行 ,只有正常退出循环才有下一页
        for col in range(1,5):  #每一行多少个商品也就是多少列,因为最后一个是item-last所以这里不能选节点
            row=str(row)
            col=str(col)
            try:
                d=wait.until(EC.element_to_be_clickable((By.XPATH,'//div[@class="J_TItems"]//div[@class="item4line1"]['+row+']//dl['+col+']/dd[@class="thumb"]/preceding-sibling::*[1]//img')))
                #d.click()#打开物品
                print(d.text)
                browser.execute_script("(arguments[0]).click()",d) #用脚本点击不用刷新
                switchWindows(browser,3)#切这个窗口才能打印
                    #点击了商品check一下
                shoe=wait.until(EC.presence_of_element_located((By.XPATH,'//h1[@data-spm="1000983"]'))).text
                print('型号:'+shoe)
                sales=wait.until(EC.presence_of_element_located((By.XPATH,'//span[@class="tm-count"]'))).text
                print('月销量:'+sales)
                try:
                    promoteprice=wait.until(EC.presence_of_element_located((By.XPATH,'//dl[@class="tm-promo-panel tm-promo-cur"]//span[@class="tm-price"]'))).text
                    print('促销价格¥:'+promoteprice)
                except:
                        promoteprice='不做促销'
                        print(promoteprice)

                sales=wait.until(EC.presence_of_element_located((By.XPATH,'//dl[@id="J_StrPriceModBox"]//span[@class="tm-price"]'))).text
                print('原价格:¥'+sales)
                browser.close()       #打印完关闭
                switchWindows(browser,2)        #切回去
                #browser.refresh()            #刷新
            except:
                print("找不到商品")
                return  browser #找完商品了测试有没有下一页
    return browser #找完商品了测试有没有下一页
def nextPage(browser):
    
    #time.sleep(3) #挺十秒在爬
    #browser.refresh()  #在nextpage这里出错
    wait=wdw(browser,10)
    try:
        nextPage=wait.until(EC.presence_of_element_located((By.XPATH,'//a[@class="J_SearchAsync next"]')))
        print(nextPage.text)
        browser.execute_script("(arguments[0]).click()",d) #用脚本点击不用刷新
        print(browser)
        return browser,True
    except: 
        browser.close()
        switchWindows(browser,1)
        print('nextPage没有下一页')
        print(browser)
        return browser,False       #没有下一页了  
def getImformation(browser):
    Class=2
    while True:
        
        browser=nextClass(browser,Class)  #打开第一个分类

        print('打开第几个分类了')
        print(Class)
        while True:
            browser=getGoods(browser)
            browser,isNextPage=nextPage(browser)
            print(isNextPage)
            if isNextPage==False:
                print('没有下一页')
                break
        Class+=1
        if Class==13:
            break

def checkAction():
    pyautogui.moveTo(837+318,479+10)
    pyautogui.mouseDown()
    pyautogui.moveTo(837+318,479+10+50)
    pyautogui.mouseUp()
    pyautogui.moveTo(800,479+10+100+30)
    pyautogui.mouseDown()
    pyautogui.moveTo(1200,479+10+100+30)
    pyautogui.mouseUp()
    
def check(browser):  #把这个函数弄成多线程函数然后挂起它,一旦遇到问题了在调用
    mutex = threading.Lock()
    wait=wdw(browser,5)#验证模块少等一点,而寻找模块等久一点,防止出现验证模块的时候切换到了寻找模块
    while True:
        mutex.acquire()
        print('执行一次')
        try:
            wait.until(EC.presence_of_element_located((By.XPATH,'//div[@id="J_sufei"]')))
            print('验证成功')
            checkAction()
            browser.refresh() #验证成功要刷新一次才能获取
            handle=browser.current_window_handle
            browser.switch_to_window(handle)
            time.sleep(30) #每次验证了久等待
            #return browser  如果return回去的话线程就会死掉
            #except:
                #print('未找到验证模块')  #一旦没有找打验证模块说明,只是因为没有刷新才遇到了问题
                #handle=browser.current_window_handle
                #browser.refresh() #验证成功要刷新一次才能获取
                #browser.switch_to_window(handle)
                #return browser
        except:
            print('没有检测到模块')
        mutex.release()


    

if __name__=='__main__':
    browser=__login__('username','password','G:/jupyter project/淘宝/block_blue.PNG','G:/jupyter project/淘宝/block_red.PNG')
    browser=openPage(browser)
    threads=[]
    t1=threading.Thread(target=getImformation,args=(browser,))
    #getImformation(browser)
    threads.append(t1)
    t2=threading.Thread(target=check,args=(browser,))
    threads.append(t2)
    for t in threads:
        t.setDaemon(True)
        t.start()
    
    
                        
                        
                        
                        

到此为止就可以爬某宝了,ip池就迟点更新了,在写完这个多线程爬某宝之后,深感自己对反爬认识的不足,暂时还不知道怎么去分析页面的js,来确定到底如何做到反爬的。之所以没放弃是因为,考虑到某宝这种体量的公司,如果真的去分析它的反爬机制,然后有针对的绕过的话,那真是大大的增加获取数据的成功,而像我这样的骚操作也就有意义了。所以接下来就要去学习怎么分析js

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值