Python爬虫基础学习


前言

本博客仅做学习笔记,如有侵权,联系后即刻更改

科普:


学习参考网站

概述

安全

爬⾍在法律上是不被禁⽌的

  • 像王欣说过,技术是⽆罪的. 主要看你⽤它来⼲嘛

robots.txt协议

  • 规定了⽹站中哪些数据可以被爬⾍爬取,哪些数据不可以被爬取
    在这里插入图片描述

简单爬虫

爬百度首页

# 爬虫: 通过编写程序来获取到互联网上的资源
# 百度
# 需求: 用程序模拟浏览器. 输入一个网址. 从该网址中获取到资源或者内容
# python搞定以上需求. 特别简单
from urllib.request import urlopen

url = "http://www.baidu.com"
resp = urlopen(url)

with open("mybaidu.html", mode="w") as f:
    f.write(resp.read().decode("utf-8"))  # 读取到网页的页面源代码
print("over!")

web请求过程

浏览器渲染

  • 请求到服务器的时候
    服务器直接把数据全部写⼊到html中, 我们浏览器就能直接拿到带有数据的html内容

客户端渲染

  • 是第⼀次请求服务器返回⼀堆HTML框架结构
    然后再次请求到真正保存数据的服务器, 由这个服务器返回数据, 最后在浏览器上对数据进⾏加载

HTTP协议

Hyper Text Transfer Protocol(超⽂本传输协议)

  • ⽤于从万维⽹(WWW:World Wide Web )服务器传输超⽂本(HTML)到本地浏览器的传送协议

请求和响应都分为三部分

请求头中重要部分

  1. User-Agent : 请求载体的身份标识(⽤啥发送的请求)
  2. Referer: 防盗链(这次请求是从哪个⻚⾯来的? 反爬会⽤到)
  3. cookie: 本地字符串数据信息(⽤户登录信息, 反爬的token)

响应头中⼀些重要的内容:

  1. cookie: 本地字符串数据信息(⽤户登录信息, 反爬的token)
  2. 各种神奇的莫名其妙的字符串(⼀般都是token字样, 防⽌各种攻击和反爬)

请求方式分为get和post(隐式提交)
在这里插入图片描述在这里插入图片描述

requests模块⼊⻔

第三⽅模块requests

  • 这个模块的优势就是⽐urllib还要简单, 并且处理各种请求都⽐较⽅便

使用方法

既然是第三⽅模块, 那就需要我们对该模块进⾏安装

  • pip install requests

如果安装速度慢的话可以改⽤国内的源进⾏下载安装.

  • pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests

爬搜狗搜索

# 安装requests
# pip install requests
# 国内源
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests

import requests
query = input("输入一个你喜欢的明星")

url = f'https://www.sogou.com/web?query={query}'

dic = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36"
}

resp = requests.get(url, headers=dic)  # 处理一个小小的反爬

print(resp)
print(resp.text)  # 拿到页面源代码

爬百度翻译

注意百度翻译这个url不好弄出来. 记住, 在输⼊的时候, 关掉各种输⼊法,要⽤英⽂输⼊法, 然后不要回⻋. 就能看到这个sug了
在这里插入图片描述

import requests

url = "https://fanyi.baidu.com/sug"

s = input("请输入你要翻译的英文单词")
dat = {
    "kw": s
}

# 发送post请求, 发送的数据必须放在字典中, 通过data参数进行传递
resp = requests.post(url, data=dat)
print(resp.json())  # 将服务器返回的内容直接处理成json()  => dict


爬豆瓣

有⼀些⽹站在进⾏请求的时候会校验你的客户端设备型号

import requests

url = "https://movie.douban.com/j/chart/top_list"

# 重新封装参数
param = {
    "type": "24",
    "interval_id": "100:90",
    "action": "",
    "start": 0,
    "limit": 20,
}

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36"
}

resp = requests.get(url=url, params=param, headers=headers)

print(resp.json())

数据解析

网页数据提取

  1. re解析
  2. bs4解析
  3. xpath解析
    这三种⽅式可以混合进⾏使⽤, 完全以结果做导向, 只要能拿到你想要的数据. ⽤什么⽅案并不重要.当你掌握了这些之后. 再考虑性能的问题

re解析

Regular Expression, 正则表达式

⼀种使⽤表达式的⽅式对字符串进⾏匹配的语法规则

  • 我们抓取到的⽹⻚源代码本质上就是⼀个超⻓的字符串, 想从⾥⾯提取内容.⽤正则再合适不过了
    在线测试正则表达式

正则表达式相关概念

元字符

  • 具有固定含义的特殊符号

常用元字符
在这里插入图片描述
在这里插入图片描述
量词: 控制前⾯的元字符出现的次数
在这里插入图片描述
贪婪匹配和惰性匹配
在这里插入图片描述

re模块

常用功能

  • findall
    查找所有. 返回list
  • search
    会进⾏匹配. 但是如果匹配到了第⼀个结果. 就会返回这个结果. 如果匹配不上search返回的则是None
  • match
    只能从字符串的开头进⾏匹配
  • finditer
    和findall差不多. 只不过这时返回的是迭代器(重点)
  • compile()
    可以将⼀个⻓⻓的正则进⾏预加载. ⽅便后⾯的使⽤
  • 正则中的内容如何单独提取?
    单独获取到正则中的具体内容可以给分组起名字
    将正则表达式括号包裹,加?P<分组名字>
    例子:(?P<分组>\d+)
import re

# # findall:  匹配字符串中所有的符合正则的内容
# lst = re.findall(r"\d+", "我的电话号是:10086, 我女朋友的电话是:10010")
# print(lst)
#
# # finditer: 匹配字符串中所有的内容[返回的是迭代器], 从迭代器中拿到内容需要.group()
# it = re.finditer(r"\d+", "我的电话号是:10086, 我女朋友的电话是:10010")
# for i in it:
#     print(i.group())

# # search, 找到一个结果就返回, 返回的结果是match对象. 拿数据需要.group()
# s = re.search(r"\d+", "我的电话号是:10086, 我女朋友的电话是:10010")
# print(s.group())


# # match是从头开始匹配
# s = re.match(r"\d+", "10086, 我女朋友的电话是:10010")
# print(s.group())

# # 预加载正则表达式
# obj = re.compile(r"\d+")
#
# ret = obj.finditer("我的电话号是:10086, 我女朋友的电话是:10010")
# for it in ret:
#     print(it.group())
#
# ret = obj.findall("呵呵哒, 我就不信你不换我1000000000")
# print(ret)

s = """
<div class='jay'><span id='1'>郭麒麟</span></div>
<div class='jj'><span id='2'>宋铁</span></div>
<div class='jolin'><span id='3'>大聪明</span></div>
<div class='sylar'><span id='4'>范思哲</span></div>
<div class='tory'><span id='5'>胡说八道</span></div>
"""

# (?P<分组名字>正则) 可以单独从正则匹配的内容中进一步提取内容
obj = re.compile(r"<div class='.*?'><span id='(?P<id>\d+)'>(?P<wahaha>.*?)</span></div>", re.S)  # re.S: 让.能匹配换行符

result = obj.finditer(s)
for it in result:
    print(it.group("wahaha"))
    print(it.group("id"))






爬⾖瓣TOP250电影信息

# 拿到页面源代码.   requests
# 通过re来提取想要的有效信息  re
import requests
import re
import csv

url = "https://movie.douban.com/top250"
headers = {
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36"
}
resp = requests.get(url, headers=headers)
page_content = resp.text

# 解析数据
obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)'
                 r'</span>.*?<p class="">.*?<br>(?P<year>.*?)&nbsp.*?<span '
                 r'class="rating_num" property="v:average">(?P<score>.*?)</span>.*?'
                 r'<span>(?P<num>.*?)人评价</span>', re.S)
# 开始匹配
result = obj.finditer(page_content)
f = open("data.csv", mode="w")
csvwriter = csv.writer(f)
for it in result:
    # print(it.group("name"))
    # print(it.group("score"))
    # print(it.group("num"))
    # print(it.group("year").strip())
    dic = it.groupdict()
    dic['year'] = dic['year'].strip()
    csvwriter.writerow(dic.values())

f.close()
print("over!")

爬屠戮天堂

# 1. 定位到2020必看片
# 2. 从2020必看片中提取到子页面的链接地址
# 3. 请求子页面的链接地址. 拿到我们想要的下载地址....
import requests
import re

domain = "https://www.dytt89.com/"

resp = requests.get(domain, verify=False)  # verify=False 去掉安全验证
resp.encoding = 'gb2312'  # 指定字符集
# print(resp.text)

# 拿到ul里面的li
obj1 = re.compile(r"2020必看热片.*?<ul>(?P<ul>.*?)</ul>", re.S)
obj2 = re.compile(r"<a href='(?P<href>.*?)'", re.S)
obj3 = re.compile(r'◎片  名(?P<movie>.*?)<br />.*?<td '
                  r'style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">', re.S)

result1 = obj1.finditer(resp.text)
child_href_list = []
for it in result1:
    ul = it.group('ul')

    # 提取子页面链接:
    result2 = obj2.finditer(ul)
    for itt in result2:
        # 拼接子页面的url地址:  域名 + 子页面地址
        child_href = domain + itt.group('href').strip("/")
        child_href_list.append(child_href)  # 把子页面链接保存起来


# 提取子页面内容
for href in child_href_list:
    child_resp = requests.get(href, verify=False)
    child_resp.encoding = 'gb2312'
    result3 = obj3.search(child_resp.text)
    print(result3.group("movie"))
    print(result3.group("download"))
    # break  # 测试用

bs4解析

基于HTML语法解析

  • <标签 属性=“值”> 被标记的内容</标签>
  • <标签 属性=“值”/>

bs4模块

python中推荐⽤pip进⾏安装

  • pip install bs4

如果安装的速度慢, 建议更换国内源(推荐阿⾥源或者清华源)

  • pip install -i https://pypi.tuna.tsinghua.edu.cn/simple bs4

BeautifulSoup对象

获取html中的内容主要通过两个⽅法来完成

  • find(标签, 属性=值)
    意思是在⻚⾯中查找 xxx标签, 并且标签的xxx属性必须是xxx值
    找到一个就返回
  • find_all()

抓取北京新发地的农产品价格

# 安装
# pip install bs4 -i 清华

# 1. 拿到页面源代码
# 2. 使用bs4进行解析. 拿到数据
import requests
from bs4 import BeautifulSoup
import csv

url = "http://www.xinfadi.com.cn/marketanalysis/0/list/1.shtml"
resp = requests.get(url)

f = open("菜价.csv", mode="w")
csvwriter = csv.writer(f)

# 解析数据
# 1. 把页面源代码交给BeautifulSoup进行处理, 生成bs对象
page = BeautifulSoup(resp.text, "html.parser")  # 指定html解析器
# 2. 从bs对象中查找数据
# find(标签, 属性=值)
# find_all(标签, 属性=值)
# table = page.find("table", class_="hq_table")  # class是python的关键字
table = page.find("table", attrs={"class": "hq_table"})  # 和上一行是一个意思. 此时可以避免class
# 拿到所有数据行
trs = table.find_all("tr")[1:]
for tr in trs:  # 每一行
    tds = tr.find_all("td")  # 拿到每行中的所有td
    name = tds[0].text  # .text 表示拿到被标签标记的内容
    low = tds[1].text  # .text 表示拿到被标签标记的内容
    avg = tds[2].text  # .text 表示拿到被标签标记的内容
    high = tds[3].text  # .text 表示拿到被标签标记的内容
    gui = tds[4].text  # .text 表示拿到被标签标记的内容
    kind = tds[5].text  # .text 表示拿到被标签标记的内容
    date = tds[6].text  # .text 表示拿到被标签标记的内容
    csvwriter.writerow([name, low, avg, high, gui, kind, date])

f.close()
print("over1!!!!")

爬优美图库

# 1.拿到主页面的源代码. 然后提取到子页面的链接地址, href
# 2.通过href拿到子页面的内容. 从子页面中找到图片的下载地址 img -> src
# 3.下载图片
import requests
from bs4 import BeautifulSoup
import time

url = "https://www.umei.cc/bizhitupian/weimeibizhi/"
resp = requests.get(url)
resp.encoding = 'utf-8'  # 处理乱码

# print(resp.text)
# 把源代码交给bs
main_page = BeautifulSoup(resp.text, "html.parser")
alist = main_page.find("div", class_="TypeList").find_all("a")
# print(alist)
for a in alist:
    href = a.get('href')  # 直接通过get就可以拿到属性的值
    # 拿到子页面的源代码
    child_page_resp = requests.get(href)
    child_page_resp.encoding = 'utf-8'
    child_page_text = child_page_resp.text
    # 从子页面中拿到图片的下载路径
    child_page = BeautifulSoup(child_page_text, "html.parser")
    p = child_page.find("p", align="center")
    img = p.find("img")
    src = img.get("src")
    # 下载图片
    img_resp = requests.get(src)
    # img_resp.content  # 这里拿到的是字节
    img_name = src.split("/")[-1]  # 拿到url中的最后一个/以后的内容
    with open("img/"+img_name, mode="wb") as f:
        f.write(img_resp.content)  # 图片内容写入文件

    print("over!!!", img_name)
    time.sleep(1)


print("all over!!!")

Xpath解析

XPath是⼀⻔在 XML ⽂档中查找信息的语⾔

  • XPath可⽤来在 XML⽂档中对元素和属性进⾏遍历
    可以⽤xpath去查找html中的内容

Xpath模块

python中想要使⽤xpath, 需要安装lxml模块

  • pip install lxml

  • 将要解析的html内容构造出etree对象.

  • 使⽤etree对象的xpath()⽅法配合xpath表达式来完成对数据的提

python项目中导入方法

之前的直接使用:from lxml import etree #后边的etree就会显示不可用

  • 是lxml中没有etree包,ppython3.5之后的 lxm 模块l中不能再直接引入etree模块,虽然新版本无法直接”fromlxml import etree“这样,但是,它只不过是换了一个办法引出 etree而已,具体如下
from lxml import html
etree = html.etree

xpath使用实例

# xpath 是在XML文档中搜索内容的一门语言
# html是xml的一个子集
"""
<book>
    <id>1</id>
    <name>野花遍地香</name>
    <price>1.23</price>
    <author>
        <nick>周大强</nick>
        <nick>周芷若</nick>
    </author>
</book>
"""
# 安装lxml模块
# pip install lxml -i xxxxxx
# xpath解析
from lxml import html

etree = html.etree


xml = """
<book>
    <id>1</id>
    <name>野花遍地香</name>
    <price>1.23</price>
    <nick>臭豆腐</nick>
    <author>
        <nick id="10086">周大强</nick>
        <nick id="10010">周芷若</nick>
        <nick class="joy">周杰伦</nick>
        <nick class="jolin">蔡依林</nick>
        <div>
            <nick>热热热热热1</nick>
        </div>
        <span>
            <nick>热热热热热2</nick>
        </span>
    </author>

    <partner>
        <nick id="ppc">胖胖陈</nick>
        <nick id="ppbc">胖胖不陈</nick>
    </partner>
</book>
"""

tree = etree.XML(xml)
# result = tree.xpath("/book")  # /表示层级关系. 第一个/是根节点
# result = tree.xpath("/book/name")
# result = tree.xpath("/book/name/text()")  # text() 拿文本
# result = tree.xpath("/book/author//nick/text()")  # // 后代
# result = tree.xpath("/book/author/*/nick/text()")  # * 任意的节点. 通配符(会儿)
result = tree.xpath("/book//nick/text()")
print(result)

查找b.html的相关信息

b.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Title</title>
    </head>
    <body>
        <ul>
            <li><a href="http://www.baidu.com">百度</a></li>
            <li><a href="http://www.google.com">谷歌</a></li>
            <li><a href="http://www.sogou.com">搜狗</a></li>
        </ul>
        <ol>
            <li><a href="feiji">飞机</a></li>
            <li><a href="dapao">大炮</a></li>
            <li><a href="huoche">火车</a></li>
        </ol>
        <div class="job">李嘉诚</div>
        <div class="common">胡辣汤</div>
    </body>
</html>

python代码

from lxml import html

etree = html.etree

tree = etree.parse("b.html")
# result = tree.xpath('/html')
# result = tree.xpath("/html/body/ul/li/a/text()")
# result = tree.xpath("/html/body/ul/li[1]/a/text()")  # xpath的顺序是从1开始数的, []表示索引

# result = tree.xpath("/html/body/ol/li/a[@href='dapao']/text()")  # [@xxx=xxx] 属性的筛选

# print(result)

# ol_li_list = tree.xpath("/html/body/ol/li")
#
# for li in ol_li_list:
#     # 从每一个li中提取到文字信息
#     result = li.xpath("./a/text()")  # 在li中继续去寻找. 相对查找
#     print(result)
#     result2 = li.xpath("./a/@href")  # 拿到属性值: @属性
#     print(result2)
#
# print(tree.xpath("/html/body/ul/li/a/@href"))

print(tree.xpath('/html/body/div[1]/text()'))
print(tree.xpath('/html/body/ol/li/a/text()'))


爬八戒网

# 拿到页面源代码
# 提取和解析数据
import requests
from lxml import html

etree = html.etree

url = "https://beijing.zbj.com/search/f/?type=new&kw=saas"
resp = requests.get(url)
# print(resp.text)

# # 解析
html = etree.HTML(resp.text)
#
# # 拿到每一个服务商的div
# print(html.xpath('//*[@id="__layout"]/div/div[3]/div/div[4]/div[4]/div[1]/div[1]/div/div[3]/div[2]/a/text()'))

divs = html.xpath('//*[@id="__layout"]/div/div[3]/div/div[4]/div[4]/div[1]/div')
for div in divs:  # 每一个服务商信息
    title = "saas".join(div.xpath("./div/div[2]/div[2]/a/text()")) if "saas".join(div.xpath("./div/div[2]/div[2]/a/text()")) != '' else "saas".join(div.xpath("./div/div[3]/div[2]/a/text()"))
    # //*[@id="__layout"]/div/div[3]/div/div[4]/div[4]/div[1]/div[1]/div/div[3]/div[2]/a
    com_name = div.xpath(".//div/a/div[2]/div[1]/div/text()")[0].strip('')
    # //*[@id="__layout"]/div/div[3]/div/div[4]/div[4]/div[1]/div[1]/div/a/div[2]/div[1]/div
    # location = div.xpath("./div/div/a[2]/div[1]/div/span/text()")[0]
    print(f'''
    {title}: {com_name}
    ''')


总结

小小励志

有些事你现在不做,一辈子都不会做了。
如果你想做一件事,全世界都会为你让路。
《搭车去柏林》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值