🙇前言
教程面向对象:
爬虫学习入门者(大佬对我写的不好的地方也请您多多指教哇)
本人爬虫基础:
这个暑假学习了大约40天,中间踩过很多坑,希望能分享一些自己的见解和学习方法,提高入门学习的效率。
初次分享文章,希望大家多多关照丫~
阅读本文需要知识储备 或者 你可以学习到:
①python基础,定义函数/类,使用循环,使用模块和相关方法,用列表,文件操作等(可以根据代码返学习知识点)
②网页基础:会运用requests模块解析静态网页(对静态网页的解析),了解网页的基础知识
③BeautifulSoup和Xpath是获取数据两个常用的方法,知道这两个的存在,可以结合本文学习到常用的语法操作,相对于前面的两个,Selenium算是比较进阶的内容,在此可以稍作接触,为后面正式接触作铺垫
④会运用查看网页源码的操作,**不懂的建议结合一些入门视频查看会更形象一些,后面会涉及三种常用的基本操作
⑤数据保存的两种形式,openpyxl和csv模块的运用,会讲到一点,可以结合我后续分享的案例进行深入
学习建议:
①分解代码编写步骤:解析网页、获取数据、保存数据,按函数编写,提高代码的复用性(比如解析网页,我们会经常用到,练习的时候不需要重复编写,复制过来或进行少许特殊改动即可,数据保存同理,我们需要重点训练的是获取数据的过程)
②可以通过案例积累常用的获取数据的方法、思路、代码
③案例拓展:学会按照一个案例进行改动拓展知识点的学习,比如将本案例用多进程操作来提高爬虫速度或转换为scrapy框架的写法(这两点我练习的还不够多,所以不好误导大家)
🔉网页分析
一 与BeautifulSoup有关|标签定位
运用BeautifulSoup方法时需要定位的是标签(紫色内容),会结合一些特殊属性和属性值来进行定位,
等号左边的是属性,右边的是属性值
运用Cirl+F来进行搜索:
(以下是我目前掌握到的思路)
①将所想要运用的定位标签判断是否只属于想要获取内容
②如果该内容在其它位置也有的话,对其特有的属性和属性值进行判断,attrs={}的参数输入(本案例有用到)常用是class_="xxx"进行判断(注意class后面还有 _ 该符号)
③如果该内容只是该标签所有,则只需要find该标签
二 与xpath有关 | 路径定位
是定位xpath的,此时重点依旧是要找到所要获取的内容信息,在上图定位到数据所在地方之后右键复制xpath
三 与本教程无关的json形式获取
在如图所示的位置(如果没有响应需要刷新/等待才展示名称所在栏的内容),将所要获取的内容进行搜索,
得到的是json形式的分析方法(该方法可以用于爬取微博评论/爬取喜马拉雅音频)
如下图所示,我们以此形式对内容进行定位(这个展示需要下载谷歌的json插件)
总结:用标签/path/json来进行定位,至于怎么定位,先按照教程所给的代码去寻找,进行分析。可以进行适当的变式操作是,对课程没有爬取的内容进行定位来爬取(先模仿然后再自己去找,掌握找的思路)
☄️保存数据
储存内容常用的代码块(这里移用了我爬过的案例代码),保存为csv文件或者Excel
备注:items 是一个列表,该列表内部又是多个列表(每一层爬取到的内容)
#前提:import csv
def save(items):
with open('豆瓣读书list.csv', 'w', encoding='utf-8') as f:
csvwriter = csv.writer(f)
csvwriter.writerows(items)
#前提:import openpyxl
def savesheet(items):
wk = openpyxl.Workbook()
sheet = wk.active
#以下是定义表头的内容
sheet['A1'] = '书名'
sheet['B1'] = '信息'
sheet['C1'] = '描述'
for item in items:
sheet.append(item)
wk.save('booklist.xlsx')
🕵️三种方法
📑内容摘要:
方法一:用xpath(该案例最简单的用法)
方法二:用selenium,是基于xpath方法来进行的
(但有点大材小用了,selenium适用于爬取JavaScript渲染的动态网页,而requests模块无法得到此类网页的全部内容,可以爬取b站评论区/爱彼迎网站的一些图片等)
特点是不需要用到requests方法,可以为以后学Selenium学点基础知识,Selenium也常与BeautifulSoup结合使用
方法三:用BeautifulSoup,但代码比较复杂,会附上源码但暂时不讲了
📝阅读建议:
①根据重点讲解进行理解,不懂的可以发在评论区,我会尽所能帮助解决不懂的点
②涉及openpyxl和csv两种数据保存的方法,可以借此加深一下使用
③可以延伸思考:
实现翻页操作/爬取网页内的其它数据怎么写代码/如何提高爬取的速度/
csv的其它写法,比如列表中保存为多个字典/如何优化代码,让代码更加简洁等等
xpath方法
源码
import requests
import csv
from lxml import etree
def get_resp(url):
resp = requests.get(url,timeout=30)
resp.encoding = 'utf-8'
resp = resp.text
return resp
def save(items):
with open('软科.csv', 'w', encoding='utf-8') as f:
csvwriter = csv.writer(f)
csvwriter.writerows(items)
def get_data(resp):
tree = etree.HTML(resp)
names = tree.xpath(
'//*[@id="content-box"]/div[2]/table/tbody/tr/td[2]/div/div[2]/div[1]/div/div/a/text()')
names = [name.replace(' ', '').replace('\n', '') for name in names]
provinces = tree.xpath('//*[@id="content-box"]/div[2]/table/tbody/tr/td[3]/text()')
provinces = [province.replace(' ', '').replace('\n', '') for province in provinces]
types = tree.xpath('//*[@id="content-box"]/div[2]/table/tbody/tr/td[4]/text()')
types = [types.replace(' ', '').replace('\n', '') for type in types]
scores = tree.xpath('//*[@id="content-box"]/div[2]/table/tbody/tr/td[5]/text()')
scores = [score.replace(' ', '').replace('\n', '') for score in scores]
items = []
for i in range(len(names)):
item = [f'UNIVERSITY:{names[i]}', f'PROVINCES:{provinces[i]}', f'SCORES:{scores[i]}', f'TYPES:{types[i]}']
items.append(item)
save(items)
if __name__ == '__main__':
url = 'https://www.shanghairanking.cn/rankings/bcur/2023'
resp = get_resp(url)
get_data(resp)
重点讲解
names = tree.xpath(
#//*[@id="content-box"]/div[2]/table/tbody/tr[1]/td[2]/div/div[2]/div[1]/div/div/a
'//*[@id="content-box"]/div[2]/table/tbody/tr/td[2]/div/div[2]/div[1]/div/div/a/text()')
names = [name.replace(' ', '').replace('\n', '') for name in names]
结合前面的网页分析xpath的方法,以一个数据为例,右键复制xpath过来
注意点
①此处要将tr[1]>>tr:实现从单个例子转换为普遍的抓取,如下图,存在多个tr,我们要实现的是从每个tr中获取
大学名,省市这些数据的xpath
②如果后面复制过来没有/text(),自己补上即可,意思是获取这个的文本
③双击源代码中的“清华大学“会看到有换行和空格的存在,需要进行数据处理,第四行用的是列表推导式(常用),将names中的name进行统一处理
for i in range(len(names)):
item = [f'UNIVERSITY:{names[i]}', f'PROVINCES:{provinces[i]}', f'SCORES:{scores[i]}', f'TYPES:{types[i]}']
items.append(item)
def save(items):
with open('软科.csv', 'w', encoding='utf-8') as f:
csvwriter = csv.writer(f)
csvwriter.writerows(items)
这是常见的数据储存的形式,另一种同样csv方式的写法可以看BeautifulSoup中写法
最终结果如图:
Selenium方法
使用前提:
①安装Edge驱动器(需要版本相同)并安装到系统环境变量中
②Edge可以换为谷歌,同样需要下载同版本驱动器,然后改动代码中的import和find_element语法
③如果selenium还没学,也可以在学习selenium之后拿这个练练手,蛮基础的
源码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
from selenium.webdriver.common.by import By
import openpyxl
items = []
def get_driver():
options = Options()
options.add_argument('--headless')
options.add_argument("--disable-gpu")
options.add_argument('--no-sandbox')
driver = webdriver.Edge(options=options)
return driver
def save(items):
wk = openpyxl.Workbook()
sheet = wk.active
sheet['A1'] = '大学'
sheet['B1'] = '省份'
sheet['C1'] = '类型'
sheet['D1'] = '分数'
for item in items:
sheet.append(item)
wk.save('rank.xlsx')
def get_data(url):
driver = get_driver()
driver.get(url)
count = 1
for count in range(1,31):
name_path = f'//*[@id="content-box"]/div[2]/table/tbody/tr[{count}]/td[2]/div/div[2]/div[1]/div/div/a'
province_path = f'//*[@id="content-box"]/div[2]/table/tbody/tr[{count}]/td[3]'
type_path = f'//*[@id="content-box"]/div[2]/table/tbody/tr[{count}]/td[4]'
score_path = f'//*[@id="content-box"]/div[2]/table/tbody/tr[{count}]/td[5]'
name = driver.find_element(By.XPATH, name_path)
province = driver.find_element(By.XPATH, province_path)
type = driver.find_element(By.XPATH, type_path)
score = driver.find_element(By.XPATH, score_path)
name = name.text.replace(' ', '').replace('\n', '')
province = province.text.replace(' ', '').replace('\n', '')
type = type.text.replace(' ', '').replace('\n', '')
score = score.text.replace(' ', '').replace('\n', '')
item = [name, province, type, score]
items.append(item)
count += 1
save(items)
if __name__ == '__main__':
url = 'https://www.shanghairanking.cn/rankings/bcur/2023'
get_data(url)
语法重点
for count in range(1,31):
name_path = f'//*[@id="content-box"]/div[2]/table/tbody/tr[{count}]/td[2]/div/div[2]/div[1]/div/div/a'
容易出错的点是:
①后面不再有/text()
②要结合count进行遍历,最终要记得count+=1
name = driver.find_element(By.XPATH, name_path)
name = name.text.replace(' ', '').replace('\n', '')
①Edge和Chrome的语法是不一样的(但本质区别不大)
②数据处理之前需要先用.text将webelement元素转换为字符串,之后与xpath同理
def save(items):
wk = openpyxl.Workbook()
sheet = wk.active
sheet['A1'] = '大学'
sheet['B1'] = '省份'
sheet['C1'] = '类型'
sheet['D1'] = '分数'
for item in items:
sheet.append(item)
wk.save('rank.xlsx')
对于这些代码是什么意思,将代码复制后运行一下,点开得到的表格就能get到了,如下图
BeautifulSoup方法
这里涉及的要点比较多,不太适合入门,有机会再仔细分析一下,大家也可以根据源码进行研究一下
import requests
import csv
from bs4 import BeautifulSoup
items = []
def get_resp(url):
resp = requests.get(url, timeout=30)
resp.encoding = 'utf-8'
resp = resp.text
return resp
def get_data(resp):
soup = BeautifulSoup(resp, 'html.parser')
names = soup.find_all('a', class_='name-cn')
names = [name.get_text(strip=True).replace('\n', '') for name in names]
lists = soup.find_all('tr', attrs={'data-v-4645600d': ''})
items = []
ranks = []
provinces = []
types = []
for lis in lists:
infos = lis.find_all('td', attrs={'data-v-4645600d': '', 'class': ''})
if len(infos) >= 4:
rank = infos[0].get_text(strip=True)
ranks.append(rank)
province = infos[1].get_text(strip=True)
provinces.append(province)
type = infos[2].get_text(strip=True)
types.append(type)
for rank, name, province, type in zip(ranks, names, provinces, types):
item = [rank, name, province, type]
items.append(item)
save(items)
def save(items):
with open('软科.csv', 'w', encoding='utf-8') as f:
csvwriter = csv.writer(f)
csvwriter.writerows(items)
if __name__ == '__main__':
url = 'https://www.shanghairanking.cn/rankings/bcur/2023'
resp = get_resp(url)
get_data(resp)