开始前的工作:
我选择用scrapy框架来写爬虫,安装scrapy框架也是一个挺艰辛的路程。我先尝试不用国内镜像网站来安装,果然不行;然后使用国内镜像网站,代码:pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple ,速度果然飞起但最后还是安装失败。上CSDN上找原因,发现还需要先安装一个twisted库,需要在https://www.lfd.uci.edu/~gohlke/pythonlibs/上找到跟本机python版本和位数一致的版本下载,然后在cmd上安装,代码:pip install (twisted的位置)/(twisted文件名)。然后就可以用镜像网站轻松安装scrapy。
开始后:
我按照我买的书上的步骤编写爬虫,发现settings文件里有很多既定的注释,而书上并无解释,上CSDN上查,发现大部分就算翻译过来也不是我能看懂的,但也学到了写爬虫也要尽量不给别人网站造成压力,不然就会有封号的危险。
根据组长推荐和翻书后,发现用selenium更简便。改用selenium。
开始前工作:
cmd代码:pip install Selenium -i https://pypi.tuna.tsinghua.edu.cn/simple 安装selenium框架
开始后:
使用selenium框架需要先安装浏览器驱动,然后需要获取输入框的id来自动输入关键字,输入关键字之后再获取搜索的按钮,然后点击,但是发现洛谷网页源代码中输入框是无id值的,所以需要从其祖宗元素开始往下定位。好不容易敲完几层元素后,便开始自动输入关键字,但是却报出寻找不到元素的错误。发现搜索框源代码中class="frame lfe-form-sz-middle"的frame和lfe-form-sz-middle间有个空格,只用删去二者其一即可定位元素。定位搜索按钮时,发现按钮的clas_name和搜索框的class_name相同,还是使用xpath来定位比较简单,因为网页源代码中可以直接复制下xpath格式的元素位置信息。
卡在了不知道如何获取跳转之后页面的链接上。用了.get_attribute(‘href’)完美解决。
在获得通过率和提交量出用了re模块,正则表达式来提取整数和小数,十分方便。
来到了最后导入excel表格的阶段,用了xlwt库。
这三天自学爬虫,遇到问题很多很多,主要是卡在定位上,因为我是没有html基础的,还得从头认识各种标签。后面的步骤看着其他爬虫样例也能看懂并学习。
需要学习的东西还有很多,希望头能秃得慢一点。
import requests
import re # 用于提取数字
import time
import string
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait # 用于等待网页加载完成
from selenium.webdriver.support import expected_conditions as EC # 用于指定等待网页加载结束的条件
from selenium.webdriver.common.by import By # 用于指定HTML文件中DOM标签元素
import xlwt
options = webdriver.FirefoxOptions() # 设置火狐驱动器的环境
browser = webdriver.Firefox(options=options) # 创建一个火狐驱动器
url = 'https://www.luogu.com.cn/problem/list'
# 用于存字典
data_list = []
# 开始爬取
def start_crawler():
# 请求url
browser.get(url)
# 显示等待输入框是否加载完成
WebDriverWait(browser, 1000).until(
EC.presence_of_all_elements_located(
( # 洛谷网页源代码里面输入框无ID值,需要从其祖宗元素开始往下定位(从网页源代码处复制即可)
By.XPATH, "/html/body/div/div[2]/main/div/section/div/section[1]/div[1]/div/div/input")
)
)
for i in ['p', 'sp', 'cf', 'at', 'UVA']:
search_key = browser.find_element_by_class_name("frame")
search_key.clear()#清空搜索框后再输入
search_key.send_keys(i) # 找到输入框的位置,并输入题目关键字
browser.find_element_by_xpath(
"/html/body/div/div[2]/main/div/section/div/section[1]/div[1]/div/button").click() # 输入关键字后点击搜索
# 等待题目等信息是否加载完成
WebDriverWait(browser, 1000).until(
EC.presence_of_all_elements_located(
(
By.XPATH, "//html/body/div/div[2]/main/div/div/div/div[1]/div[2]")
)
)
# 获取标签信息的条数,确定遍历次数
divs = browser.find_elements_by_xpath('/html/body/div/div[2]/main/div/div/div/div[1]/div[2]/div')
# 确定页数
pages = re.findall(r"\d+", browser.find_element_by_class_name('total').get_attribute('textContent'))
count = 1
while (count <= int(pages[0])):
# 遍历循环
for div in divs:
# 获取题号
numb = div.find_element_by_class_name('pid').text
# 获取题目
name = div.find_element_by_class_name('title').text
# 获取算法(此处需要点击网页中的“显示算法”才能弹出算法
browser.find_element_by_xpath(
"/html/body/div/div[2]/main/div/div/div/div[1]/div[1]/div/div[4]/span/a").click()
algo = div.find_element_by_class_name('tags-wrap').text
# 获取来源(此处需要再次点击同样位置的“显示来源”才能弹出来源
browser.find_element_by_xpath(
"/html/body/div/div[2]/main/div/div/div/div[1]/div[1]/div/div[4]/span/a").click()
sour = div.find_element_by_class_name('tags-wrap').text
# 获取难度
diff = div.find_element_by_class_name(
'difficulty').text
# 获取通过率
rate0 = div.find_element_by_class_name('rate-popup').get_attribute('textContent')
rate1 = re.findall(r"\d+\.?\d*", div.find_element_by_class_name('rate-popup').get_attribute(
'textContent')) # \d匹配数字\.?匹配小数点\d*匹配小数点后的数字
sum = 0
for i in rate0:
if i in 'k':
sum = sum + 1
if sum == 0 or sum == 2:
rate = "{:.4f}".format(float(rate1[0]) / (0.000001 + float(rate1[1])))
else:
if sum == 1:
rate = "{:.4f}".format(float(rate1[0]) / (1000*(0.000001 + float(rate1[1]))))#这里我不知道如何处理分母为0的情况,因为所需数据只保留四位小数,所以就加了一个不会影响数据的数字来除去0值
# 获取网址
link = div.find_element_by_class_name(
'color-default').get_attribute('href')
# 获取提交量
hand1 = rate1[-1]
if 'k' in rate0:
hand = "{:.0f}".format(float(hand1) * 1000)
else:
hand = hand1
#
data_dict = {}
data_dict['numb'] = numb
data_dict['name'] = name
data_dict['algo'] = algo
data_dict['sour'] = sour
data_dict['diff'] = diff
data_dict['rate'] = rate
data_dict['link'] = link
data_dict['hand'] = hand
data_list.append(data_dict)
print(data_dict)
time.sleep(0.2) # 停止0.2秒
browser.find_element_by_xpath('/html/body/div/div[2]/main/div/div/div/div[2]/div/div/div/button[10]').click()
count = count + 1
browser.quit()
def main():
start_crawler()
# 创建工作簿
workbook = xlwt.Workbook(encoding = 'utf-8')
sheet = workbook.add_sheet('资料',cell_overwrite_ok=True)
head = ['题号', '题目', '算法', '来源', '难度', '通过率', '网址', '提交量']
for h in range(len(head)):
# 写入表头
sheet.write(0, h, head[h])
j = 1
for list in data_list:
k = 0
for key, data in list.items():
sheet.write(j, k, data)
k = k + 1
j = j + 1
workbook.save('D:\洛谷.xls')
if __name__ == '__main__':
main()
#爬取结果部分展示