绪论
很久没有做爬虫了,最近在公司做数据的时候整合某个数据时发现给的数据是从网站上进行下载的,但是领导的要求是定时从网站上下载做更新,这就需要我重新把爬虫的知识捡起来了。简单的记录一下处理的思路:
要爬取的网站是需要登录的,而且内部html代码有很多的JavaScript脚本,登录授权跨越了好几个网站,想要靠requests直接找到登录链接,基本上没可能
登录界面大概长这样:
html大概长这样:
抓包到的下载链接大概长这样:
-
可以发现直接抓去登陆链接不现实,中间转了很多层
-
虽然能够看到请求列表的json返回,但是试了之后发现即便拿到cookie也没办法请求到json,不知道发生了什么问题
-
尝试了一下构造form表单请求下载链接,发现可行
爬虫思路
于是有了以下方案:
- 使用selenium+chromdriver进行模拟登录
- 对登录之后的界面进行标签查找,搜索出要下载的所有文件名
- 使用requests进行下载
实践代码
- 用selenium模拟登录,这里主要需要考虑到网页的加载时间,中间一定要设置休眠,不要一股脑直接运行下去,不然可能抓不到想要的东西,cookie信息也有可能出错
from sqlalchemy.types import VARCHAR
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from selenium import webdriver
import logging # 引入logging模块
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
browser=webdriver.Chrome()
login_url="https://extranet.flex.com/sites/Lenovo_Services/SitePages/Home.aspx?RootFolder=/sites/Lenovo_Services/Reports/Depot/Billing%20Files/US&FolderCTID=0x012000527C4F4C4BD4BE4388B75097F987A7DB&View=%7b50831D58-B1E9-4DA2-8FA5-9BCF44183132%7d"
browser.get(login_url)
time.sleep(5)
browser.find_element_by_id("okta-signin-username").send_keys('yangsy7@lenovo.com')
browser.find_element_by_id("okta-signin-password").send_keys('yangSY0428!!')
browser.find_element_by_id('okta-signin-submit').click()
time.sleep(10)
download_url='https://extranet.flex.com/sites/Lenovo_Services/_layouts/15/download.aspx?'
cookie_dict=browser.get_cookies()
sess=requests.session()
jar=RequestsCookieJar()
for cookie in cookie_dict:
jar.set(cookie['name'], cookie['value'])
file_list=[]
try:
while True:
t=browser.find_element_by_xpath('//*[@id="onetidDoclibViewTbl0"]/tbody').find_elements_by_tag_name('a')
for i in range(len(t)):
link=t[i].get_attribute('href')
if 'csv' in link:
file_list.append(link)
print(len(file_list))
browser.find_element_by_id("pagingWPQ9next").find_element_by_tag_name('a').click()# 向前翻页
time.sleep(5)
except:
print('已经翻到最后一页')
- 获取到cookie和要下载的项之后,构建下载表单,用requests请求下载,并将文件保存到本地和数据库。如果文件下载不成功,会在这里重新打开运行这个脚本,知道全部下载完为止
Source=browser.current_url
Source=Source.split("RootFolder=")[0]+"RootFolder="+Source.split("RootFolder=")[1].replace("/",'%2F').split('#Inplview')[0].replace("_","%5F")+"#Inplview"+Source.split("RootFolder=")[1].replace("/",'%2F').split('#Inplview')[1]
for _,_,files_exist in os.walk('./FLEXFILE'):
print(files_exist)
data_amount=0
for each in file_list:
SourceUrl=each.split('.com')[1]
SourceUrl=SourceUrl.replace('%20',' ')
args_download={
'SourceUrl':SourceUrl,
'Source':Source
}
filename=SourceUrl.split("US/")[1]
if "LABOR" in filename:
if filename in files_exist:
print(filename+"已存在,跳过下载")
continue
print('文件%s未下载。正在下载'%filename)
try:
data=sess.get(download_url,params=args_download,cookies=jar)
print('%s下载完毕'%filename)
except:
print('%s未下载成功,正在准备重新下载'%filename)
logging.debug('%s未下载成功'%filename)
os.system('python ./FLEX数据自动更新.py')
with open('./FLEXFILE/'+filename,'w',encoding='utf-8') as f:
f.write(data.text)
print('%s保存完毕'%filename)
try:
file=pd.read_csv('./FLEXFILE/'+filename,sep='^')
except:
logging.debug('%s数据读取错误,可能存在编码问题'%filename)
column_list = file.columns.tolist()
type_dict = {}
for column in column_list:
type_dict[column] = VARCHAR()
try:
file.to_sql(name='NA_Commercial_Depot_FLEXFTP',con=engine1,index=False,if_exists='append',chunksize=1000,dtype=type_dict)
except Exception as e:
logging.debug('%s插入数据库错误 \n %s'%(filename,e))
print('%s完成数据库插入'%filename)
data_amount = data_amount + file.shape[0]
print('已经插入的数据量:%d' % data_amount)
结语
这个例子虽然不难,但是对于如何结合selenium获取cookie并把cookie交给requests使用来进行登录是比较有帮助的,希望能够对你有所帮助