个人对于webdriver的理解
webdriver模拟正常用户使用浏览器点击的过程进行数据的爬取,在理论上如果webdriver的操作足够随机的话被发现是爬虫的概率较低(不被发现!=不会碰到反爬技术)。用这种方法比较便捷的点在于你不需要再专门去伪造请求头了,请求头是由你选择的浏览器自己发送到(本文使用Edge浏览器)。(当然,大多数情况下我更倾向于傻瓜式的八爪鱼软件)
webdriver的基本操作
首先展示所用到的包:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
1. 创建webdriver对象(表现为打开浏览器,只不过这个浏览器是全新的,不包含任何cookie)
# 创建一个webdriver对象
driver = webdriver.Edge()
2. 打开一个网页(你同时可以在电脑上看到 代码所打开的网页)
driver.get('https://www.tianyancha.com/login#!')
3. 你可以使用CSS_Selector 或者XPath这两种最常用的定位元素的方式来进行元素选择. (Tips: 在网站整体结构经常变动的情况下使用CSS_Selector,由于XPath是精准定位,如果网站结构经常变的话会疯狂报错。。。血的教训),其次,css对于同时定位多个元素非常友好(具备相同属性), XPath由于路径的绝对精准,一次只可以定位到一个元素,下面展示元素的选取加上搜索框的文本输入与回车搜索(非常简单,一气呵成)
input = driver.find_element(By.CSS_SELECTOR, 'input')
input.send_keys(firm)
input.send_keys(Keys.RETURN)
下面为使用css_selector 对多个元素进行选择,这多个元素都具有相同的类名
# get the holders
for holder in driver.find_elements(By.CSS_SELECTOR,
'div[data-dim="holder"] div.right-name'):
holders.append(holder.text)
4. 当成功定位到自己需要收集的信息时,我们可以使用.text来提取文本。不需要定位的十分精确,只需要保证该元素(element)内只有你需要的文本就行。
try:
cap = driver.find_element(
By.XPATH,
"/html/body/div/div/div[3]/div[1]/div[3]/div/div[2]/div[2]/div[2]/div[1]/div/div[2]/table/tbody/tr[3]/td[2]/div",
).text
capital.append(cap)
except NoSuchElementException as e:
capital.append(["NotKnown"])
最后,总的代码以及详细注释如下:
"""
Author: 洗菜拉普达
CreateTime: 29, Oct, 2023
Comment:我这里在登陆状况下(爬太多了不让我查询了。。。只可以登录了)使用了XPath,
所以在未登录情况下可能运行是会出错的,只需要登录或改一下XPath即可(XPath在网站不稳定的情况下有点坑。。。)
"""
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
import pandas as pd
import numpy as np
import time
import random
# 读取文件
total_firms = pd.read_csv("firm_names_50.csv", header=None, names=["firm_name"])
total_firms.head()
# 启动Edge WebDriver
driver = webdriver.Edge()
# 先登录天眼查
driver.get("https://www.tianyancha.com/login#!")
user_input = input("对于未登录账户天眼查有查询限制,故请先登录天眼查,然后按enter键") # 对于未登录账户天眼查有查询限制
# 初始化两个list用于存储capital与holders
capital = []
total_holders = []
# driver = webdriver.Edge()
for firm in total_firms["firm_name"]:
# 设置随机休眠时间
sleeptime = random.randint(1, 2)
holders = []
# webdriver访问页面
driver.get("https://www.tianyancha.com/login#!")
time.sleep(sleeptime)
# 查询框输入查询公司
input = driver.find_element(By.CSS_SELECTOR, "input")
input.send_keys(firm)
input.send_keys(Keys.RETURN)
time.sleep(sleeptime)
# 跳转链接,请不要直接click,drive的current_url不会变!!!
link = driver.find_element(
By.CSS_SELECTOR, "div.index_header__x2QZ3 a"
).get_attribute("href")
driver.get(link)
time.sleep(sleeptime)
# 查找注册资本,注意有注册资本不存在的情况,故用try,except
try:
cap = driver.find_element(
By.XPATH,
"/html/body/div/div/div[3]/div[1]/div[3]/div/div[2]/div[2]/div[2]/div[1]/div/div[2]/table/tbody/tr[3]/td[2]/div",
).text
capital.append(cap)
except NoSuchElementException as e:
capital.append(["NotKnown"])
# get the holders
for holder in driver.find_elements(
By.CSS_SELECTOR, 'div[data-dim="holder"] div.right-name'
):
holders.append(holder.text)
# print((firm, holders)) # 打印纠错
total_holders.append(holders)
time.sleep(sleeptime)
# 存储至dataframe中并保存到数据库/csv文件中
total_firms["total_holders"] = total_holders
total_firms["capital"] = capital
total_firms.to_csv("firm_names_50_processed.csv", index=False, encoding="gbk")
driver.quit()