继续,书接上回,这次我通过jsrpc,也学会了不少逆向的知识,感觉对于一般的网站应该都能应付了。当然我说的是简单的网站,遇到那些混淆的,还有那种猿人学里面的题目,还是免谈了。那种需要的水平太高,我学习爬虫的目的也不是找什么工作,只是为了找数据,能够满足我找数据的需要就好。
现在我的初步问题已经解决了,原以为可以使用jsrpc一路搜集数据。可是还是遇到了新的问题。
接下来我想搜集这个网站的志愿服务项目的数据。发现这个网站的请求类型也比较复杂,要抓到某一个项目的数据,需要多次点击,定位到那个项目,而且进入项目的新页面,好像jsrpc获得的参数也是没什么用的了。
不知道为什么。可以先看一下。
这时,我知道这个query应该是也带bean参数。
那么再次截获它的i值,就可以使用rpc,获得bean参数吧,想着时这样的。
这个query,地址是:/webapi/listProjectsFortisWeb/query
那么我们就找这个请求时的i
i值有了,可以直接请求了吧。但是结果令人失望
得到的结果一直是固定的那么几个东西。即使换了i,换了参数,也会得到同样的结果。我也不太明白为什么。可能是网站需要经过几次鼠标点击,在点击的过程中,请求变了,我使用python请求,并没有抓到他那个真实的请求。
过程太复杂,我想我也研究不出来,比不了那些搞网站的。所以眼看又进入了困境。
这时候,想到了selenim。虽然一直以来都觉得selenium慢的要死。但是没办法啊,我会的,能够用的都用的差不多了,不会的也学了,学的也快吐了。不想再继续搞下去了,想着selenium慢就慢吧,好歹也是个办法。
环境配置
先安装
pip install browsermob-proxy
pip install selenium
然后需要根据自己的浏览器版本,下载相应的webdriver
我的是chrome116,需要chrome116的webdriver。
直接从官网下。下好之后放到虚拟环境里。
另外还需要 browsermobproxy的环境,也是直接百度搜,下载下来。
browsermobproxy的使用
说干就干, 但是还有一个问题,就是我怎么能让senenium返回给我一个json,也就是一个动态网站返回给我的东西,我怎么截取这个json。selenium一旦渲染出来,就是一个网页元素了。怎么抓取到服务器发给我的json呢。
这时候看到知乎上一个帖子介绍了browsermobproxy。感觉可以用,就试了一下。
确实可以。简单来说,这个库就是相当于一个python版的fiddler,只不过fiddler是集成在一个软件里面,python调用不方便。但是这个库直接安装到python里面就可以了。简单
直接pip install就可以。
然后我也放弃了使用rpc方法,直接使用python模拟鼠标点击。
简单粗暴。就是慢点。
直接上代码,
import json
from selenium.webdriver.common.keys import Keys
import numpy as np
import re
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
from browsermobproxy import Server
from selenium.webdriver.chrome.options import Options
import os
import requests
import time
js="var q=document.documentElement.scrollTop=10000"
# 开启proxy
def start_proxy(har_name):
server = Server(r'E:\code\codeForArticle2023\sdzyfw2\sdzyfw2.0\browsermob-proxy-2.1.4\bin\browsermob-proxy.bat')
server.start()
proxy = server.create_proxy()
print(proxy.proxy)
proxy.new_har(har_name, options={"captureHeaders": True, "captureContent":True})
return proxy
# 打开driver
def start_driver(proxy):
chrome_options = Options()
chrome_options.add_argument('--proxy-server={0}'.format(proxy.proxy))
chrome_options.add_argument('--ignore-certificate-errors')
chrome_options.add_experimental_option("excludeSwitches", ["ignore-certificate-errors"])
driver = webdriver.Chrome(executable_path=r'venv/Scripts/chromedriver-win64/chromedriver.exe', options=chrome_options)
driver.get("http://sd.chinavolunteer.mca.gov.cn/subsite/shandong/project")
return driver
# 进入页面
def fetch_yantai(driver):
ele = WebDriverWait(driver, 10, 0.2).until(EC.visibility_of_element_located((By.XPATH, u'//div//a[text()="烟台市"]')), u'没有发现内容')
if ele:
item = driver.find_element_by_xpath("//div//a[text()='烟台市']")
item.click()
ele = WebDriverWait(driver, 10, 0.2).until(EC.visibility_of_element_located((By.XPATH, u'//div//a[text()="芝罘区"]')), u'没有发现内容')
if ele:
item2 = driver.find_element_by_xpath("//a[text()='芝罘区']")
item2.click()
ele = WebDriverWait(driver, 10, 0.2).until(EC.visibility_of_element_located((By.XPATH, u'//div//a[text()="已结项"]')), u'没有发现内容')
if ele:
item3 = driver.find_element_by_xpath("//a[text()='已结项']")
item3.click()
def switch_to_proj_list_page(projList_pageNum):
pn = int(projList_pageNum)
print(pn)
element = driver.find_element_by_css_selector(".pages input")
element.send_keys(Keys.CONTROL + "a")
element.send_keys(Keys.DELETE)
time.sleep(2)
element.send_keys(f"{pn}")
time.sleep(2)
driver.find_element_by_xpath("//a[text()='跳转']").click()
# 获取项目并且点击 num是第几个项目
def get_proj(driver, num):
ele = WebDriverWait(driver, 10, 0.2).until(EC.visibility_of_element_located((By.CSS_SELECTOR, u'div.panel-card')), u'没有发现内容')
if ele:
panels = driver.find_elements_by_css_selector(".panel-card")
p1 = panels[num]
print(len(panels))
link = p1.find_element_by_css_selector('h2')
link.click()
win_hans = driver.window_handles
driver.switch_to.window(win_hans[-1])
#采集信息
# 进入时长公示 页面,返回 page_num
def go_to_time(driver):
# 获取项目了之后,需要进入新的一页,进入项目的详情页。
page_num = 0
ele = WebDriverWait(driver, 10, 0.2).until(EC.visibility_of_element_located((By.XPATH, "//span[text()='时长公示']")), u'没有发现内容')
# 如果出现时长公示了,那么就可以点击时长公示,让网站显示时长。
# 接下来要判断的是,是否有时长公示
if ele:
shijian = driver.find_element_by_xpath("//span[text()='时长公示']")
shijian.click()
pages = WebDriverWait(driver, 10, 0.2).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".pages")), u"没有时长页面")
print(pages)
if pages:
recordsNum = driver.find_element_by_css_selector(".pages span:last-child").text
print(recordsNum)
rn = re.search(r'共(\d+)条', recordsNum).group(1)
rn = int(rn)
page_num = int(np.ceil(rn/8))
print(page_num)
return page_num
def click_pages(driver, page_num):
if page_num == 0:
pass
# 若只有一页,那么不需要操作了,直接退出
if page_num == 1:
pass
# 若超过2页,那么需要不断点击下一页,点击下一页需要等待,这里使用显示等待
if page_num >= 2:
for i in range(2, page_num+1):
time.sleep(3)
ele = WebDriverWait(driver, 10, 0.2).until(
EC.visibility_of_element_located((By.XPATH, "//a[text()='下一页']")), u'没有发现内容')
if ele:
next_page = driver.find_element_by_xpath("//a[text()='下一页']")
next_page.click()
WebDriverWait(driver, 10, 0.2).until(
EC.visibility_of_element_located((By.XPATH, "//a[text()='下一页']")), u'没有发现内容')
# 返回结果
def get_resp(driver, proxy):
result = proxy.har
timefortisProj =[]
postfortisProj = []
inforfortisProj = []
for rs in result['log']['entries']:
if "webapi/timeFortisWeb/query" in rs['request']['url']: # 时长记录
# 时长请求 url
print(rs['request']['url'])
timefortisProj.append(rs['response']['content']['text'])
if 'getProjectInfoFortisWeb' in rs['request']['url']: # 发起人信息
print(rs['request']['url'])
inforfortisProj.append(rs['response']['content']['text'])
if 'ProjectPostFortisWeb/query' in rs['request']['url']: # 任务信息
print(rs['request']['url'])
postfortisProj.append(rs['response']['content']['text'])
dt = {
"time":timefortisProj,
"post":postfortisProj,
"info":inforfortisProj
}
return dt
def save_file(result, qu, har_name):
with open(f"sdzyfw2/sdzyfw2.0/{qu}/{har_name}.json",'w', encoding='utf-8') as f:
f.write(json.dumps(result, ensure_ascii=False))
print("success!!!")
#---------------------------------------------------------#
#---- * * ----#
#---------------------------------------------------------#
projList_pageNum = "002"
num = 3
proj_num = str(num)
har_name = "proj_" + projList_pageNum + "_"+ proj_num
print(har_name)
#建立一个 mobproxy代理,返回端口号
proxy = start_proxy(har_name)
#通过selenium打开目标网站,
driver = start_driver(proxy)
fetch_yantai(driver)
driver.execute_script(js)
if projList_pageNum != "001":
switch_to_proj_list_page(projList_pageNum)
get_proj(driver, num)
driver.execute_script(js)
# 返回一个页码
try:
page_num = go_to_time(driver)
except:
page_num = 0
driver.execute_script(js)
# 根据页码翻页
if page_num is None:
pass
else:
try:
click_pages(driver, page_num)
except:
pass
result = get_resp(driver, proxy)
qu = "zhifuqu"
save_file(result, qu, har_name)
上面的翻页部分的逻辑还没整清楚,会出现bug,暂时先放上。回头把翻页部分整理好了再修改吧。大致思想基本没啥问题。
代码也没怎么整理,大致的意思就是使用selenium呼出浏览器,然后在浏览器里面一步步找到我想要的东西,最后把这些所有的包存放到一个har里面。后期在筛选har,提取我想要的信息。
发现这个也是很无敌的,直接免去了反反爬措施。因为就是浏览器,除非网站对webdriver有检测,不然也没办法。就老老实实的一个一个爬吧。
这个过程,看上去不复杂,其实挺麻烦,要一个个执行。估计要有几千个,想了想,还是找别人帮忙吧。其实就是学习了以下mobproxy。真要这么做的话,还是挺麻烦。最好是逆向到参数,直接提取。不推荐这种方式,当然,如果没办法,那么这个真的是终极大招了。
版权归原作者 JECK_ケーキ 所有, 如有侵权,请联系我们删除。