Python爬虫实战系列(一)-request爬取网站资源

Python爬虫实战系列(一)-request爬取网站资源

python爬虫实战系列第一期



前言

提示:这里可以添加本文要记录的大概内容:
初步了解爬虫基本原理,现在开始尝试写第一个比较综合的案例,利用request库,本系列下一期会使用其他方法进行爬取,还会写一些js逆向的方法
提示:以下是本篇文章正文内容,下面案例可供参考

一、request库是什么?

具体百度 我称之为一个强大的库

二、观察网站

请添加图片描述
链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aixc4zUz-1654939110730)(https://img-blog.csdnimg./c7623df0bd9e46f3a626f9388203c1f3.png)]
点开一个视频检索发现是这样,目录为网站基本域名+datail/1,同理其他视频为baseurl + detail / n…
请添加图片描述
F12里面也可以看到href,拼接即可使用。请添加图片描述
切换目录发现URL+ page/2
请添加图片描述
点开一个看里面内容,有封面,电影名字,评分,时间等等,我们爬取他们,这不是阿瑟他爸吗,哇一个小小网站有这么大的能量,阿瑟请坐,你自己敲代码写一个爬虫
好了 基本分析就这样,首先爬取源代码的网站,进行拼接之后,爬取拼接之后的网站的数据即可,注意正则表达的写法不能写错,注意逻辑,由于我没有开发经验需要注意,先手敲,就不粘贴复制了。

三、开冲步骤

1.引入库&&定义一些基本变量

代码如下(示例):

import requests
import logging
import  re
from urllib.parse import urljoin

logging.basicConfig(level=logging.INFO,format='%(asctime)s-%(levelname)s:%(message)s')
BASE_URL = 'https://xxxx。com'
TOTAL_PAGE = 10
#requests爬取网站,re进行正则表达,logging进行输出美观,urljoin进行url拼接,BASE_URL为网站主目录,TOTAL_PAGE要爬取的页数,后期可以更改进行交互行为

2.写一个基本爬取网站的方法

代码如下(示例):

def scrape_page(url):
    logging.info('scraping %s...',url)
    try:
        response = requests.get(url)
        if response.status_code ==200:
            return response.text
        logging.error('get invalid status code %s while scraping %s',response.status_code,url )
    except requests.RequestException:
        logging.error('error occurred while scraping %s',url,exc_info=True)
# 爬取网站,code为200返回数据,否则报错,如果爬取中间过程出问题,使用requests.requestexception报错

该处使用的url网络请求的数据。


3.写一个页面url拼接方法&&调用爬取方法

由于更换下面索引会换页面,就是上面那个page/1那种,写一个拼接方法,然后直接调用上面那个爬取方法就可以爬取页面

def scrape_index(page):
    index_url = f'{BASE_URL}/page/{page}'
    return scrape_page(index_url)

4.写一个爬取源代码中链接的方法

观察源代码,搜索任意关键字,比如阿瑟父亲的霸王别鸡,请添加图片描述
ctrl+f 搜素href,由于这个比较简单,直接正则表达a标签href class=“name”,具体代码下方

def parse_index(html):
    pattern = re.compile('<a.*?href="(.*?)".*?class="name">')
    items = re.findall(pattern,html)
    if not items:
        return []
    for item in items:
        detail_url = urljoin(BASE_URL,item)
        logging.info('get detail url %s',detail_url)
        yield detail_url
python中的yield和return的区别

return返回的是一个list列表,而yield每次调用只返回一个数值,毫无疑问,使用return空间开销比较大,尤其是操作巨量数据的时候,操作一个大列表时间开销也会得不偿失

5.程序串联调用

写了个循环然后分别爬取各个网页链接数据进行拼接之后存到detail-urls列表

def main():
    for page in range(1,TOTAL_PAGE + 1):
        index_html = scrape_index(page)
        detail_urls = parse_index(index_html)
        logging.info('detail urls %s',list(detail_urls))
if __name__ == '__main__':
    main()

6.得到详情网站写一个方法对内容进行抓取

这边抓取他的封面,标题,评分,类别,简介,上映时间,有点复杂使用一个一个的正则表达进行抓取

代码如下

def parse_detail(html):
    cover_pattern = re.compile('<div data-v-63864230="" id="detail" class="m-t">.*?<img.*?src="(.*?)".*?class="cover">',re.S)
    cover = re.search(cover_pattern,html).group(1).strip() if re.search(cover_pattern,html) else None
    return{
        'cover':cover
    }
#其中的一个cover封面提取的正则表达,其他懒得写喽,复制粘贴喽,下方附上所有代码
  cover_pattern = re.compile(
        'class="item.*?<img.*?src="(.*?)".*?class="cover">', re.S)
    name_pattern = re.compile('<h2.*?>(.*?)</h2>')
    categories_pattern = re.compile(
        '<button.*?category.*?<span>(.*?)</span>.*?</button>', re.S)
    published_at_pattern = re.compile('(\d{4}-\d{2}-\d{2})\s?上映')
    drama_pattern = re.compile('<div.*?drama.*?>.*?<p.*?>(.*?)</p>', re.S)
    score_pattern = re.compile('<p.*?score.*?>(.*?)</p>', re.S)

    cover = re.search(cover_pattern, html).group(
        1).strip() if re.search(cover_pattern, html) else None
    name = re.search(name_pattern, html).group(
        1).strip() if re.search(name_pattern, html) else None
    categories = re.findall(categories_pattern, html) if re.findall(
        categories_pattern, html) else []
    published_at = re.search(published_at_pattern, html).group(
        1) if re.search(published_at_pattern, html) else None
    drama = re.search(drama_pattern, html).group(
        1).strip() if re.search(drama_pattern, html) else None
    score = float(re.search(score_pattern, html).group(1).strip()
                  ) if re.search(score_pattern, html) else None

    return {
        'cover': cover,
        'name': name,
        'categories': categories,
        'published_at': published_at,
        'drama': drama,
        'score': score
    }

他的这个cover正则跟我不一样,他的比较简单,我懒得一个一个找哈哈,阿瑟请坐。

7.改写main函数进行一系列爬取数据

def main():
    for page in range(1,TOTAL_PAGE + 1):
        index_html = scrape_index(page)
        detail_urls = parse_index(index_html)
        for detail_url in detail_urls:
            detail_html = scrape_detail(detail_url)  #扒网站源代码
            data = parse_detail(detail_html)    #正则抓取数据进行输出
            logging.info('get detail data %s',data)

运行

8.保存数据到json

import  json
from  os import  makedirs
from os.path import exists

RESULTS_DIR = 'results'
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)

创建目录,如果存在就直接保存,不存在就创建一个文件夹

写一个方法进行保存
def save_data(data):
    name = data.get('name')
    data_path = f'{RESULTS_DIR}/{name}.json'
    json.dump(data,open(data_path,'w',encodings='utf-8'),ensure_ascil = False,indent=2)

json.dump进行改变json格式,确保是文字正常输出,并且首行缩进两个字符

9.进行再次改写main一系列爬取保存

def main():
    for page in range(1,TOTAL_PAGE + 1):
        index_html = scrape_index(page)
        detail_urls = parse_index(index_html)
        for detail_url in detail_urls:
            detail_html = scrape_detail(detail_url)
            data = parse_detail(detail_html)
            logging.info('get detail data %s',data)
            logging.info('saving data to json file')
            save_data(data)
            logging.info('data saved successfully')

爬虫完成,写出很多文件

9.修改main使用多进程加快速度

import multiprocessing

def main(page):
    index_html = scrape_index(page)
    detail_urls = parse_index(index_html)
    for detail_url in detail_urls:
            detail_html = scrape_detail(detail_url)
            data = parse_detail(detail_html)
            logging.info('get detail data %s',data)
            logging.info('saving data to json file')
            save_data(data)
            logging.info('data saved successfully')


if __name__ == '__main__':
    pool = multiprocessing.Pool()
    pages = range(1,TOTAL_PAGE + 1)
    pool.map(main,pages)
    pool.close()
    pool.join()

总结

request库简单进行爬取数据,还需努力,一些函数还得搜索才能进行,比如logging这些输出还不熟悉,还有yield需要看一下。。。。。。。。加油吧

审核啊我有网站的图片都删了,网站也都没出现,怎么就版权问题了??????

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值