版权声明:本文为博主原创文章,未经博主允许不得转载。 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(' ', ' ').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(' ', ' ').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)