多彩投网站动态爬取[python+selenium]
目標(biāo)網(wǎng)站
遇到的坑
這個網(wǎng)站為了反爬蟲,使用了很多策略,而這些策略都會是爬蟲中可能遇到的坑。
目的: 目的是爬取這個網(wǎng)頁中的這個狀態(tài)的項(xiàng)目(projectStatus=6)(估計(jì)是表示結(jié)束了的意思)
坑1
- 坑: 上面的圖示網(wǎng)頁,無法直接獲得具體的項(xiàng)目的網(wǎng)頁鏈接: 頁面的地址是被動態(tài)加載的。也就是說沒辦法直接獲取到每個項(xiàng)目的具體鏈接。
- 解決方式: 這個是被我后面用一個方法(selenium)一起解決了,但其實(shí)不是一定要用selenium的。但是如果是只有這一個問題的話,我們其實(shí)一方面可以通過后臺來看network相關(guān)的請求,另一方面看js的過程。
坑2
- 坑: 在每一個項(xiàng)目頁面中,加載到具體的具體信息頁面中。采用的是js自動替換頁面的技術(shù)。同樣是這個原因,讓我更想使用selenium來實(shí)現(xiàn)爬取了
- 解決方式: selenium動態(tài)模擬
坑3
- 坑:在具體的數(shù)據(jù)頁面中數(shù)據(jù)的變換。 比如說到稍微到后面的一點(diǎn)點(diǎn)的頁面的情況的哈,會發(fā)現(xiàn)網(wǎng)頁的數(shù)據(jù)內(nèi)容變了。
- 比如說,有些是:最高可投,有些是每人限投。其實(shí)本質(zhì)上是一個意思。
- "標(biāo)的公司", "項(xiàng)目公司"也是一樣的道理
- "標(biāo)的估值", "項(xiàng)目公司估值"
- 然后一開始的數(shù)據(jù)表示的話,中間是用:(中文輸入法的:),但是,在后面有些網(wǎng)頁就會是: (英文輸入法的冒號加上空格作為分隔符)
- 解決辦法: 全都是用中文的來進(jìn)行字符串替代。
坑4
- 坑:一開始的數(shù)據(jù)都是用每行用<p>來表示的,但是后來發(fā)現(xiàn),會隨機(jī)在某兩種數(shù)據(jù)直接,使用<br>(換行符來分隔)。這樣,如果采用一般的直接獲取p標(biāo)簽的話,就會出現(xiàn)bug。導(dǎo)致會在某些地方一直沒捕捉到數(shù)據(jù)。
- 解決辦法: 就是下面的代碼段。要先獲取具體的html代碼然后根據(jù)html的結(jié)構(gòu)進(jìn)行分析。隱含的坑!!(find_…之類的話,如果是不存在的話,就會報錯。但是之前說了這個是隨機(jī)的…所以只能是使用try來實(shí)現(xiàn))
坑5
- 坑:網(wǎng)頁結(jié)構(gòu)發(fā)生了變化。 以前的數(shù)據(jù)似乎跟稍微近一些的數(shù)據(jù)不太一樣。比如說關(guān)于我們想要的數(shù)據(jù)的所在的定位span。以前是第一個,但是后面的時候會遇到有些是在第二個上,所以就會出現(xiàn)一直爬不到信息的情況。
- 解決辦法: 這里的解決辦法其實(shí)還不夠完善,但是至少夠用了。就是使用最后一個。我發(fā)現(xiàn),之前的只有一個span的情況,那還是一樣,但是有兩個span的時候,數(shù)據(jù)一般是在后面的span中。所以我就直接使用了[-1]這樣的方式來進(jìn)行索引。
坑6
- 坑:每次都要手動登錄。非常麻煩,因?yàn)檫@里有需要有驗(yàn)證碼,而且,驗(yàn)證碼還是需要先手動先滑動一個東西之后,才會發(fā)到手機(jī)上的。而且,發(fā)到之后,每個手機(jī)號,每天只能發(fā)5次。這個非常坑。
- 解決方法: 使用pickle來存儲cookies。然后每次只用調(diào)用一次,以后的,就需要先訪問登錄網(wǎng)頁,然后加載cookies就好了。根據(jù)我的實(shí)驗(yàn),每一份cookies可以使用一天,然后,對面的這個網(wǎng)站,就會刷新這個cookies。
具體的代碼片段:
- refresh 表示是否刷新cookies
坑7
- 坑:有些是有項(xiàng)目的價值,有些是有項(xiàng)目公司的價值,有些是兩者都有 這個我驚呆了。
- 解決方法: 我就想到用字典來存儲,如果有就添加進(jìn)去,否則就添加一個NULL。
坑8
- 坑:這個網(wǎng)頁有些神奇(或許是服務(wù)器質(zhì)量不是很好),有些時候網(wǎng)頁加載數(shù)據(jù)的速度很慢。(加載的延時很高)。有時候,爬取到了具體的數(shù)據(jù),但是卻沒爬到對應(yīng)的公司名字。這個沒辦法了。
- 解決辦法: 我就設(shè)置,如果當(dāng)公司名字為空的話,就重新加載。然后最多重新加載一定的次數(shù)。
類似的有切換網(wǎng)頁的時候也會出現(xiàn)失敗,但是刷新一下也就好了。這個我就限制了,到了一定次數(shù)就直接終止整個程序。因?yàn)?#xff0c;我有天晚上爬取,但是半夜的時候斷網(wǎng)了… 發(fā)現(xiàn)一直在爬取空數(shù)據(jù)。所以就有了這樣的設(shè)計(jì)。
同時,我也增加了等待機(jī)制。 類似于下面的這種。
elemnt = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[3]/ul/li[%d]/div/div/div[1]/div[2]/h3' % (index_i + 1))))同樣是因?yàn)槟谴瓮k?#xff0c;我之前爬取到不少有用的數(shù)據(jù),但是沒保存,所以我加入了一個中途定次數(shù)記錄的代碼。來保持中間的數(shù)據(jù),為避免突然發(fā)生的問題。
坑9
- 到很久遠(yuǎn)的數(shù)據(jù)時候,會發(fā)現(xiàn)沒有數(shù)據(jù)了,全都是圖片來表示數(shù)據(jù)
- 這是我一個沒解決的問題: 在圖片內(nèi)… 我大概就爬了300多條稍微干凈的數(shù)據(jù)了,我想應(yīng)該夠用了吧。
- 在圖片內(nèi)嵌入數(shù)據(jù),這個只能做圖片文字提取的技術(shù)了。。
代碼如何使用
- pageCount 第幾頁(是最開始的圖片所示)
- index_i在第幾頁的第幾個(從0開始計(jì)數(shù))
用這個可以做分段爬取(有時候遇到問題了,對于某些部分可以用這個來設(shè)置重新開始)
-
refresh = False 為True的時候,需要手動登錄。然后,等待出現(xiàn)刷新完成之后就說明已經(jīng)保存好cookies了。然后以后再啟動的時候,就設(shè)置為False。這樣就不需要再登錄了。
-
configure 這個部分的代碼,一般人都需要注釋掉。我有這個代碼,主要是因?yàn)槲业腸hrome是我用源碼替換掉的。所以沒寫入到系統(tǒng)中。然后就手動寫執(zhí)行文件所在的地址好了。一般人是不需要這段代碼的。記得注釋掉!!!
-
下載好需要的庫~
之后直接運(yùn)行就好了。用時蠻久的。
完全的代碼
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 import time import pickle import pandas as pd##################### USERNAME = "寫自己的手機(jī)號碼" # 填寫好賬號 密碼 下面的url根據(jù)要求替換掉 URL = "https://www.duocaitou.com/project?projectStatus=6&pageNum=%d" pageCount = 1 tempURL = URL % pageCount LOGIN_URL = "https://www.duocaitou.com/login?redirect=%2Fproject" refresh = False##################### # configure options = webdriver.ChromeOptions() options.binary_location = r"D:\Software\Chrome\Application\chrome.exe" browser = webdriver.Chrome(chrome_options=options)keys = ['項(xiàng)目公司', '項(xiàng)目公司估值', '項(xiàng)目估值', '籌集規(guī)模', '籌集模式', '起投金額', '每人限投', '投資期限'] globalData = {} for k in keys:globalData[k] = []if refresh:browser.get(LOGIN_URL)# 登錄time.sleep(2)input = browser.find_element_by_xpath('//input[@placeholder="請輸入手機(jī)號"]')input.send_keys(USERNAME)time.sleep(40)pickle.dump(browser.get_cookies(), open("cookies.pkl", "wb"))print('finish refresh')browser.get(tempURL) # 加載網(wǎng)頁time.sleep(2) else:browser.get(LOGIN_URL) # 加載網(wǎng)頁cookies = pickle.load(open("cookies.pkl", "rb"))for cookie in cookies:browser.add_cookie(cookie)browser.get(tempURL) # 加載網(wǎng)頁time.sleep(2)print(tempURL) save = 0 times = 0index_i = 0 continuetime = 0try:while True:try:elemnt = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[3]/ul/li[%d]/div/div/div[1]/div[2]/h3' % (index_i + 1))))li_list = browser.find_element_by_xpath('//*[@id="__layout"]/div/div[2]/div/div[3]/ul/li[%d]/div/div/div[1]/div[2]/h3' % (index_i + 1)).click()elemnt = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[1]/div[1]/div[2]/div[1]/div/div/div/div/div[3]')))browser.find_element_by_xpath('//*[@id="__layout"]/div/div[2]/div/div[1]/div[1]/div[2]/div[1]/div/div/div/div/div[3]').click()elemnt = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[1]/div[1]/div[2]/div[2]/div[2]/div/span')))datas = browser.find_elements_by_xpath('//*[@id="__layout"]/div/div[2]/div/div[1]/div[1]/div[2]/div[2]/div[2]/div/span')if "籌集模式" in datas[0].text:datas = datas[0]else:datas = datas[-1]elemnt = WebDriverWait(datas, 10).until(EC.presence_of_element_located((By.TAG_NAME, 'p')))time.sleep(5 + continuetime)datas = datas.find_elements_by_tag_name('p')[0:40]except Exception as e:browser.get(tempURL) # 加載網(wǎng)頁print('refresh', tempURL, 'index is', index_i)time.sleep(5)continuetime += 1if continuetime >= 10:breakcontinuedatas = [d for d in datas if len(d.text.strip()) > 4 and (':' in d.text or ':' in d.text)][:8]tempDatas = []for d in datas:try:td = d.find_element_by_tag_name('span').get_attribute("innerHTML")if '<br>' in td:tds = td.split('<br>')for tdi in tds:tempDatas.append(tdi.replace('\n', '').replace(' ', ' ').replace(': ', ':').replace(':', ":").strip())else:tempDatas.append(d.text.strip().replace('\n', '').replace(': ', ':').replace(':', ":"))except Exception as e:tempDatas.append(d.text.strip().replace('\n', '').replace(': ', ':').replace(':', ":"))datas = tempDatastry:tempdict = {}for d in datas:if ':' not in d:continuea = d[:d.index(':')]b = d[d.index(':') + 1:]if a == '最高可投':a = '每人限投'a = a.replace("標(biāo)的公司", "項(xiàng)目公司").replace("標(biāo)的估值", "項(xiàng)目公司估值")if a in tempdict:if '籌集規(guī)模:' in b:b = b.split('籌集規(guī)模:')tempdict['項(xiàng)目公司估值'] = b[0]tempdict['籌集規(guī)模'] = b[1]else:tempdict['項(xiàng)目公司估值'] = belif a == '籌集模式' and '每人限投:' in b:b = b.split('每人限投:')tempdict[a] = b[0]tempdict['每人限投'] = b[1]elif a == '項(xiàng)目公司' and '籌集規(guī)模:' in b:b = b.split('籌集規(guī)模:')tempdict['項(xiàng)目公司估值'] = b[0]tempdict['籌集規(guī)模'] = b[1]else:tempdict[a] = bif len(tempdict) == 0 or '項(xiàng)目公司' not in tempdict:continuetime += 1if continuetime < 3:browser.get(tempURL) # 加載網(wǎng)頁time.sleep(2)continueelse:continuetime = 0for key in globalData.keys():if key in tempdict:globalData[key].append(tempdict[key])elif key == '標(biāo)的公司':globalData['項(xiàng)目公司'].append(tempdict[key])elif key == '標(biāo)的公司估值':globalData['項(xiàng)目公司估值'].append(tempdict[key])else:globalData[key].append('NULL')print(key, ': ', globalData[key][-1], end=' , ')print()times += 1if times % 50 == 49:pd.DataFrame(globalData).to_excel('data_%d.xlsx' % save, columns=keys)save += 1times = 0except Exception as e:print(e.args)for i, d in enumerate(datas):print(i, d)breakif index_i == 8:index_i = 0pageCount += 1if pageCount >= 67:breaktempURL = URL % pageCountprint(tempURL)browser.get(tempURL) # 加載網(wǎng)頁time.sleep(2)else:browser.get(tempURL) # 加載網(wǎng)頁time.sleep(2)index_i += 1continuetime = 0 finally:pd.DataFrame(globalData).to_excel('data.xlsx', columns=keys)總結(jié)
以上是生活随笔為你收集整理的多彩投网站动态爬取[python+selenium]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RNN代码解释pytorch
- 下一篇: VS C++调用python进行画图ma