Python学习笔记:23 爬虫

简介

网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。

通过网络爬虫,我们可以爬取到网页的一些有用的信息,一个网页源代码往往很复杂,可以通过正则表达式匹配网页中我们需要的元素,以爬取到相关信息,也可以通过利用bs4库中的一些方法从网页中提取数据。

一个简单的爬虫例子

爬取豆瓣电影 Top 250的电影名字和图片。

为了避免爬取网页时ip被封,可以将requests请求到的网页源代码写入文件,再通过读取文件获取想要的信息。

import requests

url = "https://movie.douban.com/top250"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; '
                  'Win64; x64) AppleWebKit/537.36 '
                  '(KHTML, like Gecko) Chrome/92.0.4515.131 '
                  'Safari/537.36'
}
resp = requests.get(url, headers=headers)
with open('豆瓣电影.html', 'w', encoding='utf-8') as file:
    file.write(resp.text)

requests请求方法中有两个参数,第一个是网址,第二个是访问的请求头,请求头获取方法如下:

打开豆瓣电影 Top 250首页的开发者工具,找到导航栏上的Network并点击,然后刷新一下,点击任意行(一般点击第一行)。

在这里插入图片描述

找到Request Headers下的User-Agent

在这里插入图片描述

打开刚刚写好的文件,使用正则表达式匹配需要的信息。

import re

with open('豆瓣电影.html', 'r', encoding='utf-8') as file:
    content = file.read()
    # print(content)

re_str = r'<img.*?alt="(.*?)" src="(.+?)".*?>'
pattern = re.compile(re_str)
results = pattern.findall(content)
for alt, src in results:
    print(alt)
    print(src)

使用search方法匹配一条电影的名字和图片链接的信息。

import re

with open('豆瓣电影.html', 'r', encoding='utf-8') as file:
    content = file.read()
    # print(content)

re_str = r'<img width="100" alt="(.*)" ' \
         r'src="([a-z]{5}.{3}[a-z\d]{4}\.[a-z]{8}\.[a-z]{3}/view/photo/s_ratio_poster/public/p[0-9]{9}.jpg)" class="">'

result = re.search(re_str, content)
# print(result)
# span()输出匹配到的字符串的起始位置和结束位置
print(result.span())
# group(),将分组中的内容返回
# 如果参数是0,将所有分组内容输出
# print(result.group(0))
print(result.group(1))
print(result.group(2))
# groups()将正则表达式中分组的内容合成一个元组
print(result.groups())

运行结果:

(9883, 10002)
肖申克的救赎
https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg
('肖申克的救赎', 'https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg')

bs4语法

bs4(Beautiful Soup 4)是一个三方库,用之前需要安装,使用pip install beautifulsoup4命令安装即可,导入时使用import bs4导入。

import bs4

# bs4:全称:Beautiful Soup 4,可以从HTML或XML钟提取数据,
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""

soup = bs4.BeautifulSoup(html, 'lxml')
# print(soup)
# print(type(soup))
# 格式化前端源码
print(soup.prettify())

# 打印标签:只打印第一个某某标签的内容
print(soup.head)
print(soup.head.title)

# 打印标签内容:4钟方法
print(soup.head.title.string)
print(soup.head.title.get_text())
print(soup.head.title.text)
print(soup.head.title.contents)

# 选择标签内容方法
# select:使用(id、class、标签、属性、父子、后代、兄弟、相邻兄弟等选择器)去选择标签内的内容,返回的结果是一个列表
# select_one:使用(id、class、标签、属性、父子、后代、兄弟、相邻兄弟等选择标签内的内容,返回的结果是select结果中的第一个元素
p_list = soup.select('body > p')
print(p_list)

p_list1 = soup.select('body > .title')
print(p_list1)

p = soup.select_one('body > p')
print(p)

使用方法:

  • 第一步:使用bs4的接口将网页源代码生成一个bs4对象。
  • 第二步:通过对象的selectselect_one方法来提取数据。

bs4对象中有两个参数,第一个参数是网页源代码,第二个参数是lxml解析器。

下面来看一个例子:

爬取成都链家二手房的房源信息,包括标题,链接,位置,单价,总价。

import requests
import bs4

url = 'https://cd.lianjia.com/ershoufang/rs/'
headers = {
    'User-Agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                  'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
}
resp = requests.get(url, headers=headers)
# print(resp.status_code)
# print(resp.text)
soup = bs4.BeautifulSoup(resp.text, 'lxml')
# print(soup)
li_list = soup.select('body > .content > .leftContent > .sellListContent > .clear')
print(li_list)
print(len(li_list))
for i in li_list:
    # print(i)
    # print(type(i))
    # 标题
    # a标签里只有a标签的信息,可以使用select_one.text获取文本信息
    title = i.select_one('li > .info > .title > a').text
    print(title)

    # 超链接
    # attrs[属性名]可以获取标签里的对应属性
    href = i.select_one('li > .info > .title > a').attrs['href']
    print(href)

    # 位置
    # positionInfo类标签中只有a标签,可以使用select_one.text获取文本信息
    area = i.select_one('li > .info > .flood > .positionInfo').text.replace(' ', '')
    print(area)

    # 单价
    unit_price = i.select_one('li > .info > .priceInfo > .unitPrice > span').text
    print(unit_price)

    # 总价
    total_price = i.select_one('li > .info > .priceInfo > .totalPrice').text
    print(total_price)

    print('*' * 50)

代理IP爬取网页

检测代理IP是否可用

"""
此代码为代理IP可用性检测模块,可准确筛选出尚未失效IP
注:
1.此代码只针对TXT数据格式接口。
2.尚未失效IP不一定为爬虫可用IP
3.使用时,请调用check_ip(url),url为TXT数据格式接口地址
"""

import requests
import telnetlib
import re
from concurrent.futures.thread import ThreadPoolExecutor


# 请求接口,匹配出代理IP,多线程检测
def check_ip(url):
    real_ip = []

    # 检测代理IP是否失效
    def telnet_ip(ip, port):
        try:
            telnetlib.Telnet(ip, port, timeout=1)
            real_ip.append(f'{ip}:{port}')
        except:
            pass

    while True:
        try:
            resp = requests.get(url)
            # print(resp.text)
            ip_data = re.findall('(\d+\.\d+\.\d+\.\d+):(\d+)', resp.text)
            with ThreadPoolExecutor(max_workers=16) as pool:
                for ip, port in ip_data:
                    pool.submit(telnet_ip, ip, port)
            return real_ip
        except:
            pass

使用可用的代理IP爬取网页

from check_proxies import check_ip
import requests

flag = True
while flag:
    URL = 'http://api.66daili.cn/API/GetCommonProxy/?' \
          'orderid=2291244402101903832&num=20&token=66daili&format=' \
          'text&line_separator=win&protocol=http&anonymous=elite,anonymous,' \
          'transparent&area=%E4%B8%AD%E5%9B%BD&proxytype=https&speed=fast#api'
    ip_list = check_ip(URL)
    # print(ip_list)
    for i in range(len(ip_list)):
        douban_url = 'https://movie.douban.com/top250'
        headers = {
            'User-Agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                          '(KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
        }
        # 代理IP
        proxy = {
            'http': 'http://' + ip_list[i],
            'https': 'https://' + ip_list[i]
        }
        try:
            resp = requests.get(url=douban_url, headers=headers, proxies=proxy, timeout=1)
            if resp.status_code == 200:
                print(resp.text)
                flag = False
                break
        except:
            print('ERROR')

爬虫案例

爬取中国新闻网新闻类型、标题、链接、发布时间,进行多页爬取,并且只爬取当天发布的新闻。

import requests
import bs4
import time

page = 1
flag = True
while flag:

    url = f'https://www.chinanews.com/scroll-news/news{page}.html'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
    }

    resp = requests.get(url, headers=headers)
    resp.encoding = 'utf-8'
    # print(resp.text)
    page += 1
    soup = bs4.BeautifulSoup(resp.text, 'lxml')
    li_list = soup.select('body > #content > #content_right > .content_list > ul > li')
    # print(li_list)
    # print(len(li_list))
    for i in li_list:
        # print(i)
        # print(type(i))

        try:
            localtime = time.localtime()
            # 发布时间
            date = i.select_one('li > .dd_time').text
            if f'{localtime.tm_mon}-{localtime.tm_mday}' == date[:-6]:
                # 类型
                news_type = i.select_one('li > .dd_lm').text
                # 标题
                title = i.select_one('li > .dd_bt').text
                # 链接
                href = i.select_one('li > .dd_bt > a').attrs['href']
                print(news_type, title, 'https:' + href, date)
            else:
                flag = False
                break
        except Exception as err:
            print(err)

爬取到网页源代码后,发现乱码,解决办法是将请求页面的编码方式改为相对应的编码方式,可以通过查看网页源代码,获取网页的编码方式。

由于有的li标签内容为空,可以使用异常处理将错误信息打印出来。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

better meˇ:)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值