继续,书接上回,这次我通过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的环境,也是直接百度搜,下载下来。
说干就干, 但是还有一个问题,就是我怎么能让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。真要这么做的话,还是挺麻烦。最好是逆向到参数,直接提取。不推荐这种方式,当然,如果没办法,那么这个真的是终极大招了。