多彩投网站动态爬取[python+selenium]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a19990412/article/details/85066007

目标网站

在这里插入图片描述

遇到的坑

这个网站为了反爬虫,使用了很多策略,而这些策略都会是爬虫中可能遇到的坑。

目的: 目的是爬取这个网页中的这个状态的项目(projectStatus=6)(估计是表示结束了的意思

坑1

  • 坑: 上面的图示网页,无法直接获得具体的项目的网页链接: 页面的地址是被动态加载的。也就是说没办法直接获取到每个项目的具体链接。
  • 解决方式: 这个是被我后面用一个方法(selenium)一起解决了,但其实不是一定要用selenium的。但是如果是只有这一个问题的话,我们其实一方面可以通过后台来看network相关的请求,另一方面看js的过程。

坑2

  • 坑: 在每一个项目页面中,加载到具体的具体信息页面中。采用的是js自动替换页面的技术。同样是这个原因,让我更想使用selenium来实现爬取了
  • 解决方式: selenium动态模拟

坑3

  • 坑:在具体的数据页面中数据的变换。 比如说到稍微到后面的一点点的页面的情况的哈,会发现网页的数据内容变了。
    • 比如说,有些是:最高可投,有些是每人限投。其实本质上是一个意思。
    • "标的公司", "项目公司"也是一样的道理
    • "标的估值", "项目公司估值"
    • 然后一开始的数据表示的话,中间是用中文输入法的),但是,在后面有些网页就会是: (英文输入法的冒号加上空格作为分隔符)
  • 解决办法: 全都是用中文的来进行字符串替代。

坑4

  • 坑:一开始的数据都是用每行用<p>来表示的,但是后来发现,会随机在某两种数据直接,使用<br>(换行符来分隔)。这样,如果采用一般的直接获取p标签的话,就会出现bug。导致会在某些地方一直没捕捉到数据。
  • 解决办法: 就是下面的代码段。要先获取具体的html代码然后根据html的结构进行分析。隐含的坑!!(find_…之类的话,如果是不存在的话,就会报错。但是之前说了这个是随机的…所以只能是使用try来实现)
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('&nbsp;', ' ').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 = tempDatas

坑5

  • 坑:网页结构发生了变化。 以前的数据似乎跟稍微近一些的数据不太一样。比如说关于我们想要的数据的所在的定位span。以前是第一个,但是后面的时候会遇到有些是在第二个上,所以就会出现一直爬不到信息的情况。
  • 解决办法: 这里的解决办法其实还不够完善,但是至少够用了。就是使用最后一个。我发现,之前的只有一个span的情况,那还是一样,但是有两个span的时候,数据一般是在后面的span中。所以我就直接使用了[-1]这样的方式来进行索引。

坑6

  • 坑:每次都要手动登录。非常麻烦,因为这里有需要有验证码,而且,验证码还是需要先手动先滑动一个东西之后,才会发到手机上的。而且,发到之后,每个手机号,每天只能发5次。这个非常坑。
  • 解决方法: 使用pickle来存储cookies。然后每次只用调用一次,以后的,就需要先访问登录网页,然后加载cookies就好了。根据我的实验,每一份cookies可以使用一天,然后,对面的这个网站,就会刷新这个cookies

具体的代码片段:

  • refresh 表示是否刷新cookies
if refresh:
    browser.get(LOGIN_URL)
    # 登录
    time.sleep(2)
    input = browser.find_element_by_xpath('//input[@placeholder="请输入手机号"]')
    input.send_keys(USERNAME)
    time.sleep(40)
    pickle.dump(browser.get_cookies(), open("cookies.pkl", "wb"))
    print('finish refresh')
    browser.get(tempURL)  # 加载网页
    time.sleep(2)
else:
    browser.get(LOGIN_URL)  # 加载网页
    cookies = pickle.load(open("cookies.pkl", "rb"))
    for cookie in cookies:
        browser.add_cookie(cookie)
    browser.get(tempURL)  # 加载网页
    time.sleep(2)

坑7

  • 坑:有些是有项目的价值,有些是有项目公司的价值,有些是两者都有 这个我惊呆了。
  • 解决方法: 我就想到用字典来存储,如果有就添加进去,否则就添加一个NULL。

坑8

  • 坑:这个网页有些神奇(或许是服务器质量不是很好),有些时候网页加载数据的速度很慢。(加载的延时很高)。有时候,爬取到了具体的数据,但是却没爬到对应的公司名字。这个没办法了。
  • 解决办法: 我就设置,如果当公司名字为空的话,就重新加载。然后最多重新加载一定的次数。

类似的有切换网页的时候也会出现失败,但是刷新一下也就好了。这个我就限制了,到了一定次数就直接终止整个程序。因为,我有天晚上爬取,但是半夜的时候断网了… 发现一直在爬取空数据。所以就有了这样的设计。

同时,我也增加了等待机制。 类似于下面的这种。

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)))
            )

同样是因为那次停电,我之前爬取到不少有用的数据,但是没保存,所以我加入了一个中途定次数记录的代码。来保持中间的数据,为避免突然发生的问题。

坑9

  • 到很久远的数据时候,会发现没有数据了,全都是图片来表示数据
  • 这是我一个没解决的问题: 在图片内… 我大概就爬了300多条稍微干净的数据了,我想应该够用了吧。
  • 在图片内嵌入数据,这个只能做图片文字提取的技术了。。

代码如何使用

  • pageCount 第几页(是最开始的图片所示)
  • index_i在第几页的第几个(从0开始计数)

用这个可以做分段爬取(有时候遇到问题了,对于某些部分可以用这个来设置重新开始)

  • refresh = False 为True的时候,需要手动登录。然后,等待出现刷新完成之后就说明已经保存好cookies了。然后以后再启动的时候,就设置为False。这样就不需要再登录了。

  • configure 这个部分的代码,一般人都需要注释掉。我有这个代码,主要是因为我的chrome是我用源码替换掉的。所以没写入到系统中。然后就手动写执行文件所在的地址好了。一般人是不需要这段代码的。记得注释掉!!!

  • 下载好需要的库~

之后直接运行就好了。用时蛮久的。

完全的代码

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 = "写自己的手机号码"
# 填写好账号 密码 下面的url根据要求替换掉
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 = ['项目公司', '项目公司估值', '项目估值', '筹集规模', '筹集模式', '起投金额', '每人限投', '投资期限']
globalData = {}
for k in keys:
    globalData[k] = []

if refresh:
    browser.get(LOGIN_URL)
    # 登录
    time.sleep(2)
    input = browser.find_element_by_xpath('//input[@placeholder="请输入手机号"]')
    input.send_keys(USERNAME)
    time.sleep(40)
    pickle.dump(browser.get_cookies(), open("cookies.pkl", "wb"))
    print('finish refresh')
    browser.get(tempURL)  # 加载网页
    time.sleep(2)
else:
    browser.get(LOGIN_URL)  # 加载网页
    cookies = pickle.load(open("cookies.pkl", "rb"))
    for cookie in cookies:
        browser.add_cookie(cookie)
    browser.get(tempURL)  # 加载网页
    time.sleep(2)

print(tempURL)
save = 0
times = 0

index_i = 0
continuetime = 0

try:
    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)  # 加载网页
            print('refresh', tempURL, 'index is', index_i)
            time.sleep(5)

            continuetime += 1
            if continuetime >= 10:
                break
            continue
        datas = [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('&nbsp;', ' ').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 = tempDatas
        try:
            tempdict = {}
            for d in datas:
                if ':' not in d:
                    continue

                a = d[:d.index(':')]
                b = d[d.index(':') + 1:]
                if a == '最高可投':
                    a = '每人限投'
                a = a.replace("标的公司", "项目公司").replace("标的估值", "项目公司估值")
                if a in tempdict:
                    if '筹集规模:' in b:
                        b = b.split('筹集规模:')
                        tempdict['项目公司估值'] = b[0]
                        tempdict['筹集规模'] = b[1]
                    else:
                        tempdict['项目公司估值'] = b
                elif a == '筹集模式' and '每人限投:' in b:
                    b = b.split('每人限投:')
                    tempdict[a] = b[0]
                    tempdict['每人限投'] = b[1]
                elif a == '项目公司' and '筹集规模:' in b:
                    b = b.split('筹集规模:')
                    tempdict['项目公司估值'] = b[0]
                    tempdict['筹集规模'] = b[1]
                else:
                    tempdict[a] = b

            if len(tempdict) == 0 or '项目公司' not in tempdict:
                continuetime += 1
                if continuetime < 3:
                    browser.get(tempURL)  # 加载网页
                    time.sleep(2)
                    continue
                else:
                    continuetime = 0

            for key in globalData.keys():
                if key in tempdict:
                    globalData[key].append(tempdict[key])
                elif key == '标的公司':
                    globalData['项目公司'].append(tempdict[key])
                elif key == '标的公司估值':
                    globalData['项目公司估值'].append(tempdict[key])
                else:
                    globalData[key].append('NULL')
                print(key, ': ', globalData[key][-1], end=' , ')
            print()
            times += 1
            if times % 50 == 49:
                pd.DataFrame(globalData).to_excel('data_%d.xlsx' % save, columns=keys)
                save += 1
                times = 0
        except Exception as e:
            print(e.args)
            for i, d in enumerate(datas):
                print(i, d)
            break
        if index_i == 8:
            index_i = 0
            pageCount += 1
            if pageCount >= 67:
                break
            tempURL = URL % pageCount
            print(tempURL)
            browser.get(tempURL)  # 加载网页
            time.sleep(2)
        else:
            browser.get(tempURL)  # 加载网页
            time.sleep(2)
            index_i += 1
        continuetime = 0
finally:
    pd.DataFrame(globalData).to_excel('data.xlsx', columns=keys)

猜你喜欢

转载自blog.csdn.net/a19990412/article/details/85066007