python 小爬蟲 DrissionPage+BeautifulSoup

net郝發表於2024-06-16

哈嘍,大家好, 我要開始寫部落格啦💪..... 文中有不當之處, 還請多多指正~謝謝

1.前言

在網上找書籍或其他資源的時候,都會看到某些資源網站上寫著“資訊來源網際網路”。於是乎,我也開始“搭弓射箭”,找來了python老弟,幫我研究研究到底如何才能爬爬爬~。

首先, 第一版我用了requests工具, 好像是python 老弟自帶的 ... 用它不是不行, 就是不行, 用各種代理, 還是拉垮... 那就over

後來又研究了selenium, 這玩意配置起來賊費勁, 必須各種瀏覽器驅動版本對應,最後也是over

最後最後發現還挺不拉垮的DrissionPage, 也不知道那個大牛天天沒事幹,搞出個這麼好用的玩意 ...

廢話不多說, 咱們直接開幹

先看一下最後的結果截圖

2.邏輯思路

其實邏輯非常簡單:

  1. 開啟網頁
  2. 輸入百度地址
  3. 查詢關鍵字
  4. 獲取查詢到的頁面地址(頁碼數自己設定)
  5. 從獲取到的頁面中找我想要的資源 (這裡是網盤資源)
  6. 把結果寫入到excel
  7. over。over

3.函式定義

先介紹一下我都“裝載”了哪些函式:

#儲存結果佇列
data=queue.Queue()
#用它來開啟瀏覽器,百度輸入關鍵字,查詢並返回結果(查詢到的url,百度一頁有10個結果)
#key 百度查詢關鍵字
#port 埠號 這裡是個坑,因為不自定義埠號, 它就會重複使用某個埠號,多執行緒時經常錯誤, 找不到元素,因為你懂的...
def baiduGetUrl(key,port):
    #return ['http://....',*,*]
    pass
#獲取html內容,中間會有一些關閉按鈕的使用 (開啟網頁, 它給你個彈窗,你說你關不關它)
#url 地址是baidu給的...
#port 埠(隨機自定義 要大一些 你懂的)
def getHtml(url,port):
    #return page.html
    pass
#找到匹配的內容
def searchHtml(html,url):
    #soup.find_all(....) 
    #return result 
    pass
#負責“獲取html”和”找到html匹配的內容“ 
def getHtmlProc(url,port):
    pass
#負責寫入檔案
def create_excel(filename):
    pass
#主程式會開啟多程序,呼叫這個函式
#key 百度查詢關鍵字 port埠
def eachGetData(key,port):
    #獲取輸入的key 查詢到的地址,也就是call baiduGetUrl
    #遍歷地址,開啟幾個執行緒,執行getHtmlProc
    #最後將結果寫入檔案 create_excel

4.核心程式碼演示

不知道小夥伴們有沒有看懂函式定義部分, 也不知道我那麼定義有沒有毛病, 管他呢, 能執行就不錯了...

下面簡單程式碼演示一下, 文末會給出整個程式碼的連結哦~

檢視程式碼
 def baiduGetUrl(key,port):
    resultUrl=[]
    co = ChromiumOptions().headless()
    co.auto_port()
    co.set_local_port(9432+port)
    page = ChromiumPage(co)
    page.get("http://www.baidu.com", retry=999)
    page.wait.load_start()
    page('#kw').input(key)
    page("#su").click()
    page.wait.load_start()

    for i in range(1,16):
        try:
            next_page = page.ele("@text()=下一頁 >")  # 百度的下一頁
            if i!=1:
                if not next_page:
                    next_page=page.ele("@text()=下一頁 >")
                print(next_page)
                next_page.click()
                page.wait.load_start()
                time.sleep(2)
            divs=page.eles("t:h3")
            for d in divs:
                a=d.ele("t:a")
                resultUrl.append(a.attrs.get("href"))
        except Exception as ex:
            logger.error("下一頁時錯誤:"+str(ex))
            print("下一頁時錯誤:"+str(ex))
            pass
    page.close()
    print("獲取到的頁面url=%d"%len(resultUrl))
    return resultUrl
檢視程式碼
def getHtml(url,port):
    try:
        co = ChromiumOptions().headless()#
        co.auto_port()
        thread_id=threading.currentThread().ident
        r=random.Random()
        num=r.randint(1,40000)
        thisprot=9012+port+int(str(thread_id)[0:3])+num
        print("埠號: %d " %(thisprot,))
        co.set_local_port(thisprot)
        page = ChromiumPage(co)

        page.get(url, retry=999)
        page.wait.load_start()
        time.sleep(1)
        try:

            btn = page.ele("@aria-label:關閉")
            # 某些網站的關閉按鈕
            if btn:
                btn.click()
        except:
            pass
        try:
            btnimg = page.ele("@style^position: absolute;top: 16px;left: -20px;width: 16px;height: 16px")
            # csdn 關閉
            if btnimg:
                btnimg.click()
        except:
            pass
        try:
            btnbdba = page.ele("@class=close-btn")
            if btnbdba:
                btnbdba.click()
        except:
            pass
        try:
            btnin=page.ele("@id=access")
            if btnin:
                btnin.click()
        except:
            pass
        try:
            btnClose= page.ele("@class=close")
            if btnClose:
                btnClose.click()
        except:
            pass
        html=page.html
        page.close()
        print("獲取到html 內容")

        return html
    except Exception as ex:
        logger.error("獲取html遇到錯誤:"+str(ex))

        print("獲取html遇到錯誤:"+str(ex))
        return ""

這裡的找結果的方法多少有點簡陋, 會找到一些錯誤的結果, 也有一些結果已經過期(資源連結過期), 這有待完善哦。。

檢視程式碼
 def searchHtml(html,url):
    findData = []
    soup = BeautifulSoup(html, 'html.parser')
    print("獲取到html")
    textFindEle = soup.find_all(
        string=lambda text: text and (text.startswith('連結') or text.startswith(' 連結') or text.startswith(
            '百度網盤地址') or text.startswith('地址') or text.startswith('網盤地址')))
    hrefFindEle = soup.find_all('a', href=lambda href: href
                                                       and (href.startswith('https://pan.baidu.com/s')
                                                            or href.startswith('https://pan.baidu.com/share/init?')
                                                            or href.startswith('https://pan.quark.cn/s/')
                                                            or href.startswith('https://url98.ctfile.com/d')))
    print("找到結果 text=%d ,href=%d " % (len(textFindEle), len(hrefFindEle),))
    if len(textFindEle)!=0:
        for textf in textFindEle:
            prev = textf.previous_sibling
            next = textf.next_sibling
            try:
                findData.append(
                    {"prev": prev and prev.text, 'next': next and next.text, "thist": textf and textf.text, "url": url,
                     "thish": textf.attrs.get('href')})
            except:
                findData.append(
                    {"prev": prev and prev.text, 'next': next and next.text, "thist": textf and textf.text, "url": url,
                     "thish": ''})

                pass
    if len(hrefFindEle)!=0:
        for href in hrefFindEle:
            prev = href.previous_sibling
            next = href.next_sibling
            try:
                findData.append(
                    {"prev": prev and prev.text, 'next': next and next.text, "thist": href and href.text, "url": url,
                     "thish": href.attrs.get('href')})
            except:
                findData.append(
                    {"prev": prev and prev.text, 'next': next and next.text, "thist": href and href.text, "url": url,
                     "thish": ''})
                pass
    if len(findData)!=0:
        print("結果新增到佇列")
        data.put(findData)

5.這裡就要結束了

總體來看,程式碼還是可以找到一些想要的結果的。

整體優缺點的話, 個人覺得程式碼改成多程序(multiprocessing.Process,百度說是開啟子程序,不知道他有沒有騙我)然後在子程序中開啟了多個執行緒(限制3,4個同時執行)。。。 不能搞太多, 太多電腦大哥就不幹了,第三方外掛庫也不幹。。

比單執行緒要快很多, 但是, 也需要挺長時間查詢結果的。。

還有就是結果的正確性問題, 如何更精準的找到結果? ok , 此事仍待大神...

最後

感謝閱讀, 程式碼關注公眾號回覆“python小爬蟲”即可收到連結哦。 有問題隨時留言評論, 對了,點個贊再走唄

相關文章