python list find_一篇文章带你了解Python爬虫常用选择器
原创 麦自香 Python爬虫案例
当我们初学爬虫的时候,我们都会选择一些最基本的网站,往往不带任何反爬措施。比如某个博客站点,我们要爬全站的话,就顺着列表页爬到文章页,再把文章的时间、作者、正文等信息爬下来就可以了。那代码怎么写呢?
一般的情况我们都是使用 Python 的 requests 等库就够了,写一个基本的逻辑,顺着把一篇篇文章的源码获取下来,解析的话会用到 XPath、BeautifulSoup、或者正则表达式,再把文本写入存下来就完事了。代码很简单,就几个方法调用。逻辑很简单,几个循环加存储。
之所以这么说,是因为接下来我们想要对古诗文网站来进行爬取,分别用正则表达式、BeautifulSoup、Xpath、通过这些代码来给大家介绍下Python常用的选择器,以及他们之间的区别,让我们对Python的选择器有一个更深的认识。
一、正则表达式
正则表达式为我们提供了抓取数据的快捷方式。虽然该正则表达式更容易适应未来变化,但又存在难以构造、可读性差的问题。接下来我们使用正则表达式爬取古诗文网站,代码如下:
# 使用正则表达式解析网页元素
# 关键点:直接找每个个体里面相同位置的元素,用findall一次提取出来到列表中
import requests
import re
DATA = []
def getHTMLtext(url, headers, timeout=10):
try:
resp = requests.get(url, headers=headers, timeout=timeout)
resp.raise_for_status
resp.encoding = 'utf-8'
return resp.text
except:
return ''
def reParser(text):
name_list = re.findall(r'<div class="yizhu".*?<b>(.*?)</b>', text, re.S) # re.DOTALL
dynasty_list = re.findall(r'<p class="source">.*?target="_blank">(.*?)</a>', text, re.S)
author_list = re.findall(r'<p class="source">.*?target="_blank">.*?</a>.*?target="_blank">(.*?)</a>', text, re.S)
row_content_list = re.findall(r'<div class="contson".*?>(.*?)</div>', text, re.S)
content_list = []
for content in row_content_list:
temp = re.sub(r'<.*?>', '', content) # 这里一定要记得不要写成了贪婪匹配哦
content_list.append(temp.strip()) # 去除空格
for value in zip(name_list, dynasty_list, author_list, content_list):
name, dynasty, author, content = value
poetry_dict = {
'诗词名': name,
'朝代': dynasty,
'作者': author,
'内容': content,
}
DATA.append(poetry_dict)
def print_poetry(data):
for every_poetry in data:
print(every_poetry['诗词名'])
print(every_poetry['朝代'] + ':' + every_poetry['作者'])
print(every_poetry['内容'])
print("n" + '*' * 50 + "n")
if __name__ == '__main__':
row_url = '网页发生错误'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'}
num = input('请输入要爬取的页数(1-100):')
for i in range(eval(num)):
url = row_url.format(i + 1)
# print(url)
text = getHTMLtext(url, headers)
if text == '':
print('url: {} 访问失败'.format(url))
else:
reParser(text)
TOP10 = DATA[:10]
# print(TOP10)
print_poetry(TOP10)
利用正则表达式实现对目标信息的精准采集,此外 ,我们都知道,网页时常会产生变更,导致网页中会发生一些微小的布局变化时,此时也会使得之前写好的正则表达式无法满足需求,而且还不太好调试。当需要匹配的内容有很多的时候,使用正则表达式提取目标信息会导致程序运行的速度减慢,需要消耗更多内存。
二、BeautifulSoup
BeautifulSoup是一个非常流行的 Pyhon 模块,简称Bs4。该模块可以解析网页,并提供定位内容的便捷接口。通过
pip install beautifulsoup4
就可以实现该模块的安装了。演示代码如下:
# 使用bs4提取网页,先利用find_all解析
import requests
from bs4 import BeautifulSoup
DATA = []
def getHTMLtext(url, headers, timeout=10):
try:
resp = requests.get(url, headers=headers, timeout=timeout)
resp.raise_for_status
resp.encoding = 'utf-8'
return resp.text
except:
return ''
def bs4_find_all_Parser(text):
soup = BeautifulSoup(text, 'lxml')
sons = soup.find_all('div', class_="sons")[:10] # 返回一个<class 'bs4.element.ResultSet'>,每一个元素都是Tag类型
# 注意:上一步里面返回了一些其他的元素,我们可以提取出前面的10项,那是我们需要用到的
# print(sons)
for son in sons:
name = son.find('b').get_text()
print(name)
dynasty_author = son.find('p', class_="source").get_text()
print(dynasty_author)
content = son.find('div', class_="contson").get_text()
print(content)
if __name__ == '__main__':
url = '古诗文网-古诗文经典传承'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'}
text = getHTMLtext(url, headers)
if text == '':
print('url: {} 访问失败'.format(url))
else:
bs4_find_all_Parser(text)
使用 Bs4的第一步是将己下载的 HTML 内容解析为 soup文档。由于大多数网 页都不具备良好的HTML 格式,此Bs4需要对实际格式进行确定。Bs4能够正确解析缺失的引号并闭合标签,此外还会添加<html >和<body>标签使其成为完整的HTML文档。通常使用find() 和find_all()方法来定位我们需要的元素。
如果你想了解BeautifulSoup全部方法和参数,可以查阅BeautifulSoup的官方文档。虽然BeautifulSoup在代码的理解上比正则表达式要复杂一些,但是其更加容易构造和理解。
三、lxml
Xpath,使lxml 模块的第一步和BeautifulSoup一样,也是将有可能不合法的HTML 解析为统一格式。虽然lxml可以正确解析属性两侧缺失的引号,并闭合标签,不过该模块没有额外添加<html >和<body>标签 。
lxml也是需要提前安装的,通过:
pip install lxml
演示代码如下:
# xpath代码展示
import requests
from lxml import etree
DATA = []
def getHTMLtext(url, headers, timeout=10):
try:
resp = requests.get(url, headers=headers, timeout=timeout)
resp.raise_for_status
resp.encoding = 'utf-8'
return resp.text
except:
return ''
def xpathParser(text):
htmlElement = etree.HTML(text) # <class 'lxml.etree._Element'>
name_list = htmlElement.xpath('/html/body/div[2]/div[1]/div/div[1]/p[1]/a/b/text()')
dynasty_list = htmlElement.xpath('/html/body/div[2]/div[1]/div/div[1]/p[2]/a[1]/text()')
author_list = htmlElement.xpath('/html/body/div[2]/div[1]/div/div[1]/p[2]/a[2]/text()')
content_list = []
poetries = htmlElement.xpath(
'//div[@class="contson" and contains(@id,"contson")]') # 返回一个列表,里面每一个都是'lxml.etree._Element'
# print(etree.tostring(poetries[0],encoding = 'utf-8').decode('utf-8'))
for poetry in poetries:
row_content = ''.join(poetry.xpath('.//text()')) # 这里的.可千万不能掉,否则会忽略掉poetry哦
content_list.append(row_content.replace('n', ''))
for value in zip(name_list, dynasty_list, author_list, content_list):
name, dynasty, author, content = value
poetry_dict = {
'诗词名': name,
'朝代': dynasty,
'作者': author,
'内容': content,
}
DATA.append(poetry_dict)
def print_poetry(data):
for every_poetry in data:
print(every_poetry['诗词名'])
print(every_poetry['朝代'] + ':' + every_poetry['作者'])
print(every_poetry['内容'])
print("n" + '*' * 50 + "n")
if __name__ == '__main__':
row_url = '网页发生错误'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'}
num = input('请输入要爬取的页数(1-100):')
for i in range(eval(num)):
url = row_url.format(i + 1)
text = getHTMLtext(url, headers)
if text == '':
print('url: {} 访问失败'.format(url))
else:
xpathParser(text)
TOP10 = DATA[:10]
print_poetry(TOP10)
在线复制Xpath表达式可以很方便的复制Xpath表达式。但是通过该方法得到的Xpath表达式放在程序中一般不能用,而且长的没法看。所以Xpath表达式一般还是要自己亲自上手。
如果你的爬虫瓶颈是下载网页,也不是抽取数据的话,那么使用较慢的方法(如BeautifulSoup) 也不成问题。如果只需抓取少量数据,并且想要避免额外依赖的话,那么正则表达式可能更加适合。不过,通常情况下,lxml是抓取数据的最好选择,这是因为该方法既快速又健壮,而正则表达式和BeautifulSoup只在某些特定场景下有用。
Lxml模块使用 C语言编写,其解析速度比 BeautiflSoup更快,而且其安装过程也更为复杂,在此小编就不赘述啦。XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
python list find_一篇文章带你了解Python爬虫常用选择器相关推荐
- 【Python发展前景】一篇文章带你了解Python未来发展“钱”景
前言 计算机语言发展至今,已出现众多的编程语言.例如入门较难的C语言,相对通用的Java,适合初学者的Basic语言等. 但自从Python横空出世以来,以其简洁优美.功能强大.开发效率高等先天优势, ...
- excel中调用python程序_一篇文章带你使用Python搞定对Excel表的读写和处理
文章目录一.我的需求二.代码三.总结 一.我的需求 我想要excel 的最后1列由列表形式转换为数值类型 可以看到最后一列有的是列表,有的直接是数值,想要整个列表中的内容都转为数值类型 二.代码 ...
- python人脸识别防小偷_一篇文章带你了解Python 人脸识别有多简单
今天的Python学习教程给大家介绍一个世界上最简练的人脸辨认库 face_recognition,你可以应用 Python 和命令行工具进行提取.辨认.操作人脸. 基于业内领先的 C++ 开源库 d ...
- python人脸识别实验报告总结_一篇文章带你了解Python 人脸识别有多简单
原标题:一篇文章带你了解Python 人脸识别有多简单 今天的Python学习教程给大家介绍一个世界上最简洁的人脸识别库 face_recognition,你可以使用 Python 和命令行工具进行提 ...
- 一篇文章带你了解webscraper爬虫插件
点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 夜阑卧听风吹雨,铁马冰河入梦来. ...
- 有没有python的班_【万字长文】别再报班了,一篇文章带你入门Python
最近有许多小伙伴后台联系我,说目前想要学习Python,但是没有一份很好的资料入门.一方面的确现在市面上Python的资料过多,导致新手会不知如何选择,另一个问题很多资料内容也很杂,从1+1到深度学习 ...
- 万字长文,一篇文章带你入门Python
注释 Python中用#表示单行注释,#之后的同行的内容都会被注释掉. 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例 ...
- 一篇文章带你了解Python中的游戏开发模块pyglet
前言 为什么我不选择pygame,原因很简单,因为pyglet 更简单,比较轻量级,就好比django和flask的区别. 相信你在读了这篇文章之后也会毅然决然地选择pyglet. 这篇文章主要围绕p ...
- 一篇文章带你了解python装饰器
一.什么是装饰器 所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改. 这一句话理解起来可能没那么轻松,那先来看一个"傻瓜"函数. 放心,绝对不是& ...
最新文章
- 优词词根词典mdx_推荐|一波好用的在线英语词典网站
- 转帖 .Net(C#)纯GDI+绘制实时动态曲线图之二(曲线控件全部源码)
- 小学校园里计算机文字,中小学计算机教学论文(共2228字).doc
- [LeetCode] Intersection of Two Linked Lists 求两个链表的交点
- django ContentType使用方法
- Spring项目启动加载xml配置文件替换数据库提高响应速度
- JavaScript学习笔记(五)--深拷贝浅拷贝
- Flutter修仙传第一章:从Form入手学会组件使用
- linux上c语言hdc句柄,控制台窗口的绘图
- addLoadEvent方法解析
- [转]通过生日获取星座Python源码
- Python爬虫入门教程 29-100 手机APP数据抓取 pyspider
- boost::unorder_map如何插入元素_「leetcode」701. 二叉搜索树中的插入操作:【递归法】【迭代法】详解...
- android word文件编辑器,docx文档编辑
- FPGA与ASIC及SOC的区别?ARM是什么
- 夜晚网速变慢与网站服务器开机数量减少有关,网速变慢的原因及解决办法
- 前端开发和后端开发的区别
- 网站收录之采集新闻源工具
- android顶部按钮图片,安卓动态改变button顶部图片即drawableTop属性
- 链式线性表和顺序线性表
热门文章
- [moka同学笔记转载]Yii 设置 flash消息 创建一个渐隐形式的消息框
- 时间戳的转换和星期转换
- Ubuntu终端字体颜色方案
- Oracle的共享封闭 独占封闭和共享更新封闭 (1)
- Linux下如何生成core dump 文件(解决segment fault段错误的问题)
- [转]URL汉字编码问题(及乱码解决)
- 将HTMLCollection转换为数组的最有效方法
- 如何使用composer从Laravel中删除包?
- 如何修复“ sudo:不存在tty且未指定AskPass程序”错误?
- 从脚本本身获取Bash脚本的源目录