手把手学爬虫第一弹——数据获取和解析

response = requests.get(url=url, headers=headers)

response.encoding = ‘gb2312’ # 设置编码方式

if response.status_code == 200: # 判断请求是否成功

html = etree.HTML(response.text) # 解析HTML

ip = html.xpath(‘//*[@id=“list”]/table/tbody/tr/td[1]/text()’) # 获取ip内容

port = html.xpath(‘//*[@id=“list”]/table/tbody/tr/td[2]/text()’) # 获取端口号

for j in range(0, 10):

my_ip = ip[j] + ‘:’ + port[j]

print(‘代理ip为:’, ip[j], ‘对应端口为:’, port[j])

ip_list.append(my_ip)

time.sleep(1)

ip_table[‘ip’] = ip_list # 将提取的ip保存至excel文件中的ip列

生成xlsx文件

ip_table.to_excel(‘E:/python/pythonProject3/venv/Include/ip.xlsx’, sheet_name=‘data’)

b. 读取ip并判断是否可用

这种方式存在的问题就是免费网站获取的ip有国内的有国外的,有可用的有不可用的,所以存在ip是失效的问题,解决办法就是掏钱买专门的api接口。

import time

import requests # 导入网络请求模块

import pandas # 导入pandas模块

from lxml import etree # 导入HTML解析模块

ip_table = pandas.read_excel(‘E:/python/pythonProject3/venv/Include/ip.xlsx’) # 读取代理IP文件内容

ip = ip_table[‘ip’] # 获取代理ip列信息

头部信息

headers = {‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36’,

‘Accept-Language’: ‘zh-CN,zh;q=0.9’}

循环遍历代理IP并通过代理发送网络请求

for i in ip:

proxies = {‘http’: ‘http://{}’.format(i),

‘https’: ‘https://{}’.format(i)}

try:

verify=False不验证服务器的SSL证书

response = requests.get(‘http://2021.ip138.com/’, headers=headers, proxies=proxies, verify=False, timeout=10)

if response.status_code == 200: # 判断请求是否成功,请求成功说明代理IP可用

response.encoding = ‘utf-8’ # 进行编码

html = etree.HTML(response.text) # 解析HTML

info_1 = str(html.xpath(‘/html/body/p[1]/text()[1]’)).replace(“['\n”, “”).replace(“[']”, “”)

info_2 = str(html.xpath(‘/html/body/p[1]/a/text()’)).replace(“['”, “”).replace(“']”, “”)

info_3 = str(html.xpath(‘/html/body/p[1]/text()[2]’)).replace(“[‘] “, “”).replace(”\n’]”, “”)

print(info_1 + info_2 + info_3) # 输出当前ip匿名信息

time.sleep(3)

except Exception as e:

pass

print(‘错误异常信息为:’, e) # 打印异常信息

c.通过专门的API接口获取ip

import requests # 导入网络请求模块

from lxml import etree # 导入HTML解析模块

import time

url = ‘api接口’

headers = {‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36’}

response = requests.get(url=url, headers=headers)

ip = str(response.text).replace(“\r”, “”).replace(“\n”, “”)

proxies = {‘http’: ‘http://{}’.format(ip),

‘https’: ‘https://{}’.format(ip)}

print(proxies)

try:

verify=False不验证服务器的SSL证书

response = requests.get(‘http://2021.ip138.com/’, headers=headers, proxies=proxies, verify=False, timeout=10)

if response.status_code == 200: # 判断请求是否成功,请求成功说明代理IP可用

response.encoding = ‘utf-8’ # 进行编码

html = etree.HTML(response.text) # 解析HTML

info_1 = str(html.xpath(‘/html/body/p[1]/text()[1]’)).replace(“['\n”, “”).replace(“[']”, “”)

info_2 = str(html.xpath(‘/html/body/p[1]/a/text()’)).replace(“['”, “”).replace(“']”, “”)

info_3 = str(html.xpath(‘/html/body/p[1]/text()[2]’)).replace(“[‘] “, “”).replace(”\n’]”, “”)

print(info_1 + info_2 + info_3) # 输出当前ip匿名信息

time.sleep(3)

except Exception as e:

pass

print(‘错误异常信息为:’, e) # 打印异常信息

请添加图片描述


二、解析数据

==================================================================

当我们使用爬虫的时候大多数是为了爬取我们需要的部分数据,但直接获取到的往往不是我们需要的,这时候就需要我们对于爬取到的数据进行解析,进而在数据中找到我们需要的数据,接下来我将和大家一起使用正则(re)、Xpath、Beautiful Soup进行数据解析工作。

1. 正则表达式


正则表达式顾名思义就是由字符组成的表达式,这些表达式根据不同的组合可以匹配字符串中需要的部分。

(1). 正则表达式基础

a. 行定位符

行定位符用于描述字符串的边界。

| 符号 | 作用 |

| — | — |

| ^ | 表示行的开始 |

| $ | 表示行的结尾 |

b.元字符

元字符使用:

\bmr\w*\b

\b表示单词的边界

mr表示匹配开头是mr的字串

\e*表示匹配任意数量的字母或数字

该表达式可以匹配mrsoft、mrsbook、mr1234等字符串

| 代码 | 说明 |

| — | — |

| . | 匹配除换行符以外的任意字符 |

| \w | 匹配字母、数字、下划线、汉字 |

| \W | 匹配除了字母、数字、下划线、汉字以外的字符(与\w相反) |

| \s | 匹配任意空白符 |

| \S | 匹配除单个空白符(包括Tab和换行符)以外所有字符 |

| \d | 匹配数字 |

| \D | 匹配任意非数字 |

| \A | 从字符串开始处匹配 |

| \Z | 从字符串结束处匹配 |

| \b | 匹配一个单词的边界,单词分界符通常是空格、标点或者换行 |

| \B | 匹配非单词边界 |

| ^ | 匹配字符串的开始 |

| $ | 匹配字符串的结束 |

| () | 被括起来的表达式将作为分组 |

c. 限定符

上面提到"\w*"可以匹配任意数量的字母或数字。如果我们要匹配一定数量的数字,比如11位数的手机号?这时候就可以用限定符来实现。

^\d{11}$

匹配11位数的电话号码

| 符号 | 说明 | 举例 |

| — | — | — |

| ? | 匹配前面的字符零次或一次 | colour?r 可以匹配到colour和color |

| + | 匹配前面的字符一次或多次 | go+gle 可以匹配gogle到goooo…gle |

| * | 匹配前面的字符零次或多次 | go*gle 可以匹配ggle到goooo…gle |

| {n} | 匹配前面的字符串n次 | go{2}gle 只可以匹配google |

| {n,} | 匹配前面的字符最少n次 | go{2,}gle 可以匹配从google到goooo…gle |

| {n,m} | 匹配前面的字符最少n次,最多m次 | employe{0,2} 可以匹配employ、employe\employee |

d.字符类

假如我们要匹配所有大小写字母和数字,你会怎么做?列举所有的可能?显然不是,这时候我们可以使用正则表达式提供的字符类,将我们的条件放在中括号里面,例如:

[a-z0-9A-Z] # 可以匹配所有字母和数字

e. 排除字符

上面我们可以利用字符类获取我们想要的字符,那如何排除我们不需要的字符呢,很简单,在上面的表达式前面加一个^就可以了,例如:

[^a-zA-Z] # 可以匹配一个不是字母的字符

f. 选择字符

如果我们要在一堆字符里面找出所有的手机号码或者是身份证号码,如何运用正则表达式呢?分析一下身份证号码的组成,一共18位,前17位位数字,最后一位为数字或者是X,根据这一描述,我们显然可以得出如下的表达式:

[^\d{18}KaTeX parse error: Undefined control sequence: \d at position 4: |(^\̲d̲{17}(\d|X|x))

g. 转义字符

正则表达式的转义字符和python的转义字符基本没什么区别,例如当我们需要匹配的是个ip地址时,192.168.1.1中的.如何匹配呢?前面我们说到正则里面的点可以匹配一个任意字符,那这里就需要对其进行转义.

[1-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3} # 匹配ip地址

h. python中的正则表达式

在python里面我们一般不会写模式字符串,即在转义的地方加上\,这样会导致表达式中有大量的\,取而代之的是原生表达式,在表达式前面加上 R 或 r.

(2). match() 匹配

match()从字符串的开始位置匹配,如果在起始位置匹配成功就直接返回结果,反之返回None.

re.match(‘正则表达式’, ‘待匹配字符串’, ‘修饰符’)

例如:

re.match(‘mr_\w+’, ‘MR_SHOPmr_shop’, re.I)

I 表示不区分大小写

| 表达式 | 匹配效果 | 匹配结果 |

| — | — | — |

| re.match(‘mr_\w+’, ‘MR_SHOPmr_shop’, re.I) | 匹配以指定字符串开头 | <re.Match object; span=(0, 7), match=‘MR_SHOP’> |

| re,match(“.ello”, “hello”) | 匹配任意开头的字符串 | <re.Match object; span=(0, 5), match=‘hello’> |

(3). search() 匹配

search()方法不同于match()方法,search()会在整个字符串搜索第一匹配的值,匹配成功就返回,否则返回None。

re,search(“mr_\w+”, “MR_SHOP”, re.I)

re,search(“mr_\w+”, “项目名称 MR_SHOP”, re.I)

两个表示匹配结果一样

| 表达式 | 匹配效果 |

| — | — |

| \d? | 匹配多个数字,可有可无 |

| \b | 表示字符串的边界,可以是开头、结尾、空格以及换行 |

(4). findall()匹配

findall()方法会搜索整个字符串寻找符合要求的字符,并以列表的形式返回,如果没有匹配到就会返回空列表。

| 表达式 | 匹配效果 |

| — | — |

| re.findall(‘mr_\w+’, ‘MR_SHOP mr_shop’, re.I) | 所有指定字符开头的字符串 |

| re.findall(‘https://(.*)/’, ‘http://www.hao123.com/’) | 贪婪匹配,获取//开始到/前面的所有字符 |

| re.findall(‘https://(.*?)/’, ‘http://www.hao123.com/’) | 非贪婪匹配,这样可能匹配不到任何字符,因为匹配结果会尽可能少 |

(5). 字符串处理

  • 替换字符串

re.sub(‘正则表达式’, ‘要替换的字符串’, ‘要被替换的字符串’, ‘替换的最大次数,默认为0’, 修饰符)

import re

str = r’1[34578]\d{9}’

string = ‘中奖号码为3867363546 联系电话为:15071567345’

result = re.sub(str, ‘1**********’, string)

print(result)

输出结果为: 中奖号码为3867363546 联系电话为:1**********

  • 分割字符串

re.split(‘正则表达式’, ‘要匹配的字符串’, 最大拆分次数, 修饰符)

import re

str = r’[?|&]’

url = ‘http://www.baidu.com?a=12&b=3’

result = re.split(str, url)

print(result)

输出结果为: [‘http://www.baidu.com’, ‘a=12’, ‘b=3’]

2. Xpath解析


上一节我们学了正则表达式清洗数据,这一节我们学习一种更加便捷的数据清洗解析方式,XPath。这是一种基于XML的路径语言。

Xpath常用的路径表示:

| 表达式 | 描述 |

| — | — |

| nodename | 此节点的所有子节点 |

| / | 从当前节点选取子节点 |

| // | 从当前节点选取子孙节点 |

| . | 选取当前节点 |

| … | 选取当前节点的父节点 |

| @ | 选取属性class |

| * | 选取所有节点 |

这种解析方式主要熟悉网页结构,利用上面的路径表达式选取对应的路径。浏览器也提供了直接复制的Xpath路径,使用如下:

请添加图片描述

这里我就不再详细介绍这种解析方法,大家可以参考这位博主的文章,写的很详细了!Xpath解析数据

请添加图片描述

from lxml import etree

import requests

url = “https://wuhan.zbj.com/search/f/?type=new&kw=%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91”

resp = requests.get(url)

xml = resp.text

tree = etree.HTML(xml)

res = tree.xpath(‘//div[@class=“service-info-wrap”]’)

print(res)

for item in res:

price = item.xpath(‘./div[@class=“service-price clearfix”]/span/text()’)

title = item.xpath(‘./div[@class=“service-title”]/p/text()’)

result = {

“price”: ‘’.join(price),

“title”: ‘’.join(title)

}

print(result)

请添加图片描述


3. BeautifulSoup解析


BeautifulSoup是一个用于从HTML和XML中提取数据的Python库。

(1). BeautifulSoup的简单应用

使用第一步先导入bs4库,然后创建一个BeautifulSoup对象指定选用的解析器。

from bs4 import BeautifulSoup # 导入BeautifulSoup库

创建模拟HTML代码的字符串

html_doc = “”"

第一个 HTML 页面

body 元素的内容会显示在浏览器中。

title 元素的内容会显示在浏览器的标题栏中。

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

print(soup) # 打印解析的HTML代码

print(type(soup)) # 打印数据类型

这样我们就完成了数据的第一步处理工作

(2). 获取节点内容

下面以一个例子加代码注释解释如何获取节点内容。

  • 获取节点源代码

from bs4 import BeautifulSoup # 导入BeautifulSoup库

创建模拟HTML代码的字符串

html_doc = “”"

第一个 HTML 页面

body 元素的内容会显示在浏览器中。

title 元素的内容会显示在浏览器的标题栏中。

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

“”"

获取节点内容

“”"

print(‘head节点内容为:\n’, soup.head) # 打印head节点

请添加图片描述

  • 获取节点属性

在已选择的节点后面加上.attrs即可

创建模拟HTML代码的字符串

html_doc = “”"

横排响应式登录

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

print(‘meta节点中属性如下:\n’,soup.meta.attrs)

print(‘link节点中属性如下:\n’,soup.link.attrs)

请添加图片描述

  • 获取节点的文本内容

在已获取的节点后面加上.string即可。

from bs4 import BeautifulSoup # 导入BeautifulSoup库

创建模拟HTML代码的字符串

html_doc = “”"

横排响应式登录

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

print(‘titlt节点中的文本如为:’, soup.title.string)

请添加图片描述

(3). 方法获取内容

  • find_all()方法——获取所有符合条件的节点

find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwaigs)

  1. find_all(name)

通过节点名称获取内容。

soup.find_all(name=‘标签名’)

  1. find_all(attrs)

通过指定属性获取内容

soup.find_all(class=‘newslist’)

  1. fina_all(tetx)

获取指定文本内容。

soup.find_all(text=‘文本内容’)

  • find()——获取第一个匹配的节点

find()的各项参数和find_all一样,不同的是前者可以匹配所有符合匹配条件的字符,后者只能匹配第一个符合条件的字符

**tip:**还有很多其他不常用的方法,自行查阅了解。

(4). CSS选择器

  • 通过标签查找

print soup.select(‘title’) # 查找title标签

  • 通过类名查找

print soup.select(‘.sister’) # 通过class类名查找

  • 通过id名查找

print soup.select(‘#link1’) # 通过id="link2"查找

  • 组合查找

print soup.select(‘p #link1’)

查找p标签下id="link1"的内容

print soup.select(“head > title”)

查找head标签下的title标签的内容

  • 属性查找

print soup.select(‘a[class=“sister”]’)

查找a便签而且class="sister"的内容


三、爬虫项目实战

====================================================================

目标:爬取豆瓣电影top250的相关信息

第二页url: https://movie.douban.com/top250?start=25&filter=

第三页url: https://movie.douban.com/top250?start=50&filter=

正则表达式:

import re # 导入re模块

import time # 导入时间模块

import random # 导入随机模块

import requests # 导入网络请求模块

header = {‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36’}

处理字符串中的空白符,并拼接字符串

def processing(strs):

s = ‘’ # 定义保存内容的字符串

for n in strs:

n = ‘’.join(n.split()) # 去除空字符

n = n.replace(" ", “”)

s = s + n # 拼接字符串

return s # 返回拼接后的字符串

获取电影信息

def get_movie_info(url):

response = requests.get(url, headers=header) # 发送网络请求

result = response.text

li_all = re.findall(r’

  • [\s\S]*?
  • ', result)

    print(li_all[0])

    for item in li_all:

    names = re.findall(r’(.*)', item) # 获取电影名字相关信息

    name = processing(names) # 处理电影名称信息

    infos = re.findall(r’导演:(.*?)
    ', item) # 获取导演、主演等信息

    info = processing(infos) # 处理导演、主演等信息

    scores = re.findall(r’(.*)', item) # 获取电影评分

    score = processing(scores)

    evaluations = re.findall(r’(.*)', item) # 获取评分人数

    evaluation = processing(evaluations)

    summarys = re.findall(r’(.*)', item) # 获取评分人数

    summary = processing(summarys)

    print(‘电影名称:’, name)

    print(‘导演与演员:’, info)

    print(‘电影评分:’, score)

    print(‘评价人数:’, evaluation)

    print(‘电影总结:’, summary)

    print(‘--------分隔线--------’)

    if name == ‘main’:

    for i in range(0, 25, 25): # 每页25为间隔,实现循环,只爬取前5页

    通过format替换切换页码的url地址

    url = ‘https://movie.douban.com/top250?start={page}&filter=’.format(page=i)

    get_movie_info(url) # 调用爬虫方法,获取电影信息

    time.sleep(random.randint(1, 3)) # 等待1至3秒随机时间

    请添加图片描述

    Xpath:

    from lxml import etree # 导入etree子模块

    import time # 导入时间模块

    import random # 导入随机模块

    import requests # 导入网络请求模块

    header = {‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36’}

    处理字符串中的空白符,并拼接字符串

    def processing(strs):

    s = ‘’ # 定义保存内容的字符串

    for n in strs:

    n = ‘’.join(n.split()) # 去除空字符

    s = s + n # 拼接字符串

    return s # 返回拼接后的字符串

    获取电影信息

    def get_movie_info(url):

    response = requests.get(url, headers=header) # 发送网络请求

    html = etree.HTML(response.text) # 解析html字符串

    div_all = html.xpath(‘//div[@class=“info”]’)

    for div in div_all:

    names = div.xpath(‘./div[@class=“hd”]/a//span/text()’) # 获取电影名字相关信息

    name = processing(names) # 处理电影名称信息

    infos = div.xpath(‘./div[@class=“bd”]/p/text()’) # 获取导演、主演等信息

    info = processing(infos) # 处理导演、主演等信息

    score = div.xpath(‘./div[@class=“bd”]/div/span[2]/text()’) # 获取电影评分

    evaluation = div.xpath(‘./div[@class=“bd”]/div/span[4]/text()’) # 获取评价人数

    获取电影总结文字

    summary = div.xpath(‘./div[@class=“bd”]/p[@class=“quote”]/span/text()’)

    print(‘电影名称:’, name)

    print(‘导演与演员:’, info)

    print(‘电影评分:’, score)

    print(‘评价人数:’, evaluation)

    print(‘电影总结:’, summary)

    print(‘--------分隔线--------’)

    if name == ‘main’:

    for i in range(0, 125, 25): # 每页25为间隔,实现循环,只爬取前5页

    通过format替换切换页码的url地址

    url = ‘https://movie.douban.com/top250?start={page}&filter=’.format(page=i)

    get_movie_info(url) # 调用爬虫方法,获取电影信息

    time.sleep(random.randint(1, 3)) # 等待1至3秒随机时间

    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

    深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

    因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

    img

    img

    img

    img

    img

    img

    既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

    由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

    如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

    “quote”]/span/text()')

    print(‘电影名称:’, name)

    print(‘导演与演员:’, info)

    print(‘电影评分:’, score)

    print(‘评价人数:’, evaluation)

    print(‘电影总结:’, summary)

    print(‘--------分隔线--------’)

    if name == ‘main’:

    for i in range(0, 125, 25): # 每页25为间隔,实现循环,只爬取前5页

    通过format替换切换页码的url地址

    url = ‘https://movie.douban.com/top250?start={page}&filter=’.format(page=i)

    get_movie_info(url) # 调用爬虫方法,获取电影信息

    time.sleep(random.randint(1, 3)) # 等待1至3秒随机时间

    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

    深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

    因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

    [外链图片转存中…(img-TKSwGPyw-1713222469030)]

    [外链图片转存中…(img-UL4QaLiX-1713222469030)]

    [外链图片转存中…(img-PdQDUAl3-1713222469030)]

    [外链图片转存中…(img-jyaYDqm7-1713222469030)]

    img

    img

    既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

    由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

    如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

    img
  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值