文本反爬网站的分析和爬取
一、实验目的
熟悉使用Selenium、Pyppeteer等工具爬取网站基本内容,通过分析具有文本反爬技术网站,设计爬取策略来获取文本正确的内容。
二、实验预习提示
1、安装Python环境 (Python 3.x):Pychram社区版+Anaconda
2、为Python安装Selenium、PyQuery库(打开pycharm新建项目,选择Anaconda创建的Python环境,在下面对应Console窗口执行):
pip install selenium
pip install pyquery
3、安装Chrome和对应ChromeDriver:
下载安装完后查看Chrome版本:点击 Chrome 的菜单,帮助 -> 关于 Chrome,即可查看 Chrome 的版本号105.0.5195.127,如图所示:
在ChromeDriver 官方网站https://sites.google.com/chromium.org/driver/downloads下载Chrome版本对应的驱动(105.0.5195.x, 看主版本号105都行),点击下划线的链接,根据系统型号下载。windows下chromedriver_win32.zip,其他系统找到对应版本下载::
运行代码前配置系统环境变量Path前指定chrome driver位置:
Path=替换为chrome driver解压后的位置
或者在Pycharm运行配置指定:
三、实验内容
爬取网站:https://antispider3.scrape.center/
使用浏览器开发者工具(F12),分析网站结构和其中文本反爬机制,编码实现获取该网站每本书的封面图片URL、书名和作者信息。实验基框架代码见文档末资料。
四、实验要求
基本要求(60分): 将网站一页每本书的信息保存在一个josn文件中,每个json文件命名为:书名.json,其内容为保存书籍相应的信息:
{
"title": "Wonder",
"cover_url":"https://img1.doubanio.com/view/subject/l/public/s27252687.jpg",
"authors":"R. J. Palacio"
}
实现方法不一定要用Selenium、Pyppeteer,但是必须是Python编写的,并以完成实验要求为准,并附上代码运行结果。
改进要求A(80分,选做): 在完成基本要求的基础上,选项一:实现可以遍历网站的每一页来爬取书籍信息。或指定爬取条目数量,当爬取总条目满足数量后停止爬取。选项二:或者举例至少三个其他网站的文本爬虫技术,分析并给出解决方案,不需要实现。
改进要求B(100分,选做): 在完成改进要求A的选项一的基础上,可以爬取书籍的额外信息,如评分,出版时间,出版社,ISBM, 价格等。
五、实验过程
1.基本要求: 将网站一页每本书的信息保存在一个josn文件中,每个json文件命名为:书名.json,其内容为保存书籍相应的信息。
1)导入相关包
import json
import warnings
from selenium import webdriver
from pyquery import PyQuery as pq
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from bs4 import BeautifulSoup
2)通过selenium获取网页数据,初始化浏览器对象,访问网页源码,设置等待时间,以字符串形式初始化html。
def get_data(url):
data =url
#反爬
warnings.filterwarnings('ignore')
browser = webdriver.Chrome()
browser.get(data)
WebDriverWait(browser, 10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.item')))
html = browser.page_source
doc = pq(html)
3)使用BeautifulSoup解析网页
# 使用BeautifulSoup进行解析网页
object= BeautifulSoup(doc.html(), "html.parser")
browser.close()
# 书籍标签
tags = object.select("h3.name")
# 书籍名称
names = []
# 书籍作者
authors = []
# 书籍图片
pics = []
4)根据标签分析处理数据,获取书籍名称、书籍作者、书籍图片。获取书籍名称中,由于书籍名称的不同存储位置,需要分别获取书籍名称。通过lambda表达式控制文本,改变文本顺序。
# 获取书籍名称
for tag in tags:
#h3标签
if "whole" in tag.attrs['class']:
names.append(tag.text)
else:
#多个span元素
chars = tag.select("span.char")
chars = sorted(chars, key=lambda a: eval(a.attrs['style'][6:-3]))
name = ""
for char in chars:
name += char.text.strip()
names.append(name)
# 获取书籍作者
for tag in object.select("p.authors"):
authors.append(tag.text.strip().replace(" ", "").replace("\n", ""))
print()
# 获取书籍图片
for tag in object.select("img.cover"):
authors.append(tag.text.strip().replace(" ", "").replace("\n", ""))
pics.append(tag.attrs['src'])
5)运用json文件保存数据,每个json文件命名为:书名.json,json文件内容为书籍名称、书籍封面、书籍作者。
for i in range(len(names)):
#json
book = {"title": names[i],
"cover_url": pics[i],
"authors": authors[i],
}
data_path = f'{book["title"]}.json'
json.dump(book, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
6)爬取过程及结果:
Wonder.json:
人间失格.json:
2.改进要求A: 在完成基本要求的基础上,实现可以遍历网站的每一页来爬取书籍信息。
1)加入页面链接列表:
Links = [ ]
2)查找页面标签,获取链接内容,遍历页面链接。
# 获取书籍链接
tags = object.find_all('div', class_='el-col el-col-24')
print(len(tags))
for tag in [tags[i] for i in range(len(tags))]:
link = tag.find('a')
link = link.get('href')
links.append('https://antispider3.scrape.center' + link)
print(links)
return names, authors, pics, links
3)加入json文件,保存书籍数据,实现遍历网页爬取数据。
for i in range(len(names)):
#json
book = {"title": names[i],
"cover_url": pics[i],
"authors": authors[i],
"link": links[i],
}
data_path = f'{book["title"]}.json'
json.dump(book, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
4)网页前两页书籍爬取结果:
查理九世10·最后的古寺神佛.json:
设计诗.json:
3.改进要求B: 在完成改进要求A选项一的基础上,爬取书籍的额外信息,评分,价格出版社,出版时间,页数,ISBM。
1)通过BeautifulSoup解析文件,依次对每个标签进行查找处理,获取相应的书籍信息。其中需要注意书籍中没有出版社或者书籍页面的情况,需要做出更改。
def deal_data(url):
data= url
warnings.filterwarnings('ignore')
browser = webdriver.Chrome()
browser.get(data)
WebDriverWait(browser, 30).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.item')))
html = browser.page_source
doc = pq(html)
# 使用BeautifulSoup解析网页
object = BeautifulSoup(doc.html(), "html.parser")
#score
score = object.find('span', class_='score m-r m-b-sm')
if (score != None):
score = score.text
else:
score = ' '
#price
price =object.find('p', class_='price')
if (price != None):
price = price.text
else:
price = ' '
#publisher
publisher = object.find('p', class_='publisher')
if (publisher != None):
publisher = publisher.text
publisher = str(publisher).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]
else:
publisher = ' '
#publishtime
publishtime = object.find('p', class_='published-at')
if (publishtime != None):
publishtime = publishtime.text
publishtime = str(publishtime).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]
else:
publishtime = ' '
# pages
page = object.find('p', class_='page-number')
if (page != None):
page = page.text
page = str(page).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]
else:
page = ' '
#isbn
isbn = object.find('p', class_='isbn')
if (isbn != None):
isbn = isbn.text
else:
isbn = ' '
score = str(score).replace(' ', '').replace('\t', '').replace('\n', '')
price = str(price).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]
isbn = str(isbn).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]
print(score)
print(price)
print(publisher)
print(publishtime)
print(page)
print(isbn)
browser.close()
return score, price,publisher, publishtime, page,isbn
2)调用函数,遍历数据。
if __name__ == '__main__':
#url地址
url = "https://antispider3.scrape.center/page/"
for i in [i for i in range(1, 3)]:
names, pics, authors, links = get_data(url+ str(i))
scores, prices, publishers, publishtimes, pages,isbns = [], [], [], [], [], []
for link in links:
print(link)
score, price, publisher,publishtime, page, isbn = deal_data(link)
scores.append(score)
prices.append(price)
publishers.append(publisher)
publishtimes.append(publishtime)
pages.append(page)
isbns.append(isbn)
3)将书籍的评分、价格、出版社、出版时间、页面数、ISBM加入json文件,保存书籍信息。
for i in range(len(names)):
#json
book = {"title": names[i],
"cover_url": pics[i],
"authors": authors[i],
"link": links[i],
"score": scores[i],
"price": prices[i],
"scpublisherores": publishers[i],
"publishtime": publishtimes[i],
"page": pages[i],
"isbn": isbns[i],
}
data_path = f'{book["title"]}.json'
json.dump(book, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
4)爬取结果:
人间失格.json:
最美遇见你.json:
总结: 运用selenium、pyquery、beautifulsoup方法,成功实现遍历爬取网站中书籍的各类信息,并json文件保存书籍信息。
六、资料
1.实验框架代码:
from selenium import webdriver
from pyquery import PyQuery as pq
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
browser = webdriver.Chrome()
browser.get('https://antispider3.scrape.center/')
WebDriverWait(browser, 10) \
.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.item')))
html = browser.page_source
doc = pq(html)
names = doc('.item .name')
for name in names.items():
print(name.text())
2.OpenSSL:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions (slproweb.com)
3.Josn存储,先安装json包:
import json
book = {"title": "Wonder",
"cover_url":"https://img1.doubanio.com/view/subject/l/public/s27252687.jpg",
"authors":"R. J. Palacio"
}
data_path = f'{book["title"]}.json'
json.dump(book, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
4.实验小提示
可以根据HTML结构发现每个书籍信息都保存在。有的书名放在class="name whole"的H3元素,有书名由多个class="char"的SPAN元素组成。对于放在H3元素的书名,直接取出其元素内容即可,而对于放在多个SPAN元素中的书名,这里用到了文本反爬机制,利用CSS控制文本偏移来实现文本顺序改变。但不难发现其文本偏移由left属性决定原文正确顺序,因此需要按偏移left属性值大小升序排序获取正确的文本顺序。