模板第一次总结--思路

(1)
问题:爬取7天的 天气情况 日期 天气状况温度 风力–> 保存到CSV

分析需求 要干什么事情 通过什么技术来解决
爬取7天的 天气情况 日期 天气状况温度 风力–> 保存到CSV

具体步骤(分析页面)
1.先明确目标url
通过分析我们发现要爬取的数据都在 ul class=“t clearfix” 这个标签当中,然后我们就去网页的源代码中确定了
2.先获取网页的源代码 整个html文件
3.从网页的源代码当中去匹配ul标签的数据
4.从ul标签里面去匹配li标签的数据
5.去解析li标签里面的数据
5.保存数据

import requests
import re
import csv

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36'
}

class WeatherSpider:

    # 获取网页源代码
    # 类对象 实例对象 实例方法 类方法
    def getSource(self):
        # 目标url
        url = 'http://www.weather.com.cn/weather/101250101.shtml'
        resp = requests.get(url,headers=headers)
        # print(resp.content.decode('utf-8'))
        return resp.content.decode('utf-8')

    # 解析数据 保存数据
    def parseSource(self):
        content = self.getSource()
        # 匹配ul 正则表达式比较灵活 .*?ul标签前面的数据
        # 匹配并获取的 (<ul class="t clearfix">.*?</ul>)  .*?ul标签后面的数据
        result = re.match(r'.*?(<ul class="t clearfix">.*?</ul>).*?',content,re.S)
        # print(result.group(1))
        # 匹配li
        ul = result.group(1)
        lis = re.findall(r'<li.*?">.*?</li>',ul,re.S)
        lst_all = [] # 保存所有的天气数据
        pattern = re.compile(r'<li.*?">.*?<h1>(.*?)</h1>.*?<p.*?>(.*?)</p>.*?<i>(.*?)</i>.*?<i>(.*?)</i>.*?</li>',re.S)
        for li in lis:
            # lst_one = [] # 保存一天的天气数据
            r = pattern.match(li)
            # print(r.group(1),end='')
            # print(r.group(2),end='')
            # print(r.group(3),end='')
            # print(r.group(4),end='')
            # print()
            lst_one = [r.group(1),r.group(2),r.group(3),r.group(4)]
            lst_all.append(lst_one)

        return lst_all

    # 保存数据
    def saveData(self):
        content = self.parseSource()
        with open('weather7day.csv','w',encoding='utf-8',newline='') as file_obj:
            writer = csv.writer(file_obj)
            writer.writerow(['日期','天气','温度','风力'])
            writer.writerows(content)

def main():
    WeatherSpider().saveData()

if __name__ == '__main__':
    main()

(2)
豆瓣top250电影
问题: 爬取 电影的名字 评分 引言 详情页的url 保存到csv文件当中

具体步骤(分析页面)
1 明确url (是否是静态网页,对比源代码与检查)
2 先像目标url发起请求 获取网页源码
3 可以把网页源码通过 etree.HTML 生成一个element对象
element对象 通过xpath进行导航 电影的名字 评分 引言 详情页的url
4 我们可以把数据先保存到一个字典里面 {title:‘肖申克的救赎’,‘start’:9.7…} ,{title:‘霸王别姬’,‘start’:9.7…} 在把这些字典保存到一个列表当中
5 把列表中的数据存到csv文件当中

import requests
from lxml import etree
import csv

# 目标Url
doubanUrl = 'https://movie.douban.com/top250?start={}&filter='

# 定义一个函数 获取网页源码
def getSource(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36'
    }
    response = requests.get(url,headers=headers)
    response.encoding = 'utf-8'
    return response.text

# 解析数据 电影的名字 评分 引言 详情页的url
def getEveryItem(source):
    html_element = etree.HTML(source)
    # class="info" 电影的名字 评分 引言 详情页的url 25
    movieItemList = html_element.xpath('//div[@class="info"]')
    movieList = []
    for eachMoive in movieItemList:
        movieDict = {}
        title = eachMoive.xpath('div[@class="hd"]/a/span[@class="title"]/text()') # 标题
        otherTitle = eachMoive.xpath('div[@class="hd"]/a/span[@class="other"]/text()')  # 副标题
        link = eachMoive.xpath('div[@class="hd"]/a/@href')[0] # url
        star = eachMoive.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()')[0] # 评分
        quote = eachMoive.xpath('div[@class="bd"]/p[@class="quote"]/span/text()') # 引言(名句)
        # 第一种异常处理
        # 第二种非空判断
        if quote:
            quote = quote[0]
        else:
            quote = ''
        movieDict['title'] = ''.join(title + otherTitle) # 主标题要 + 父标题
        movieDict['url'] = link
        movieDict['star'] = star
        movieDict['quote'] = quote
        print(movieDict)
        movieList.append(movieDict)

    return movieList


# 保存数据 次数 Ip检测  代理Ip(付费)
def writeData(movieList):

    with open('douban.csv','w',encoding='utf-8',newline='') as file_obj:
        writer = csv.DictWriter(file_obj,fieldnames=['title','star','quote','url'])
        writer.writeheader()
        for each in movieList:
            writer.writerow(each)


if __name__ == '__main__':
    movieList = [] 

    for i in range(10):
        pageLink = doubanUrl.format(i * 25)

        source = getSource(pageLink)

        movieList = getEveryItem(source) # 保存的最后一页 movieList = movieList + getEveryItem(source)  a = 1  a += 1

    writeData(movieList)

(3)
问题:爬取中国天气网 所有城市对应的温度把数据保存到csv当中
具体步骤(分析页面)
目标url
http://www.weather.com.cn/textFC/hb.shtml 华北
http://www.weather.com.cn/textFC/db.shtml 东北

1> 我们发现每一个url 对应一个大区。所以我们先搞定一个 在去搞定其他的
2> 1. 先找到整页的 div=conMidtab 标签的数据
2. 接下来去找每一个省或者直辖市所对应的table标签
3. 找table标签里面的tr标签(需要注意 要把前2个tr过滤掉)
4. 去tr标签里面找td标签(第0个是城市 倒数第二个是温度)

import requests
from bs4 import BeautifulSoup
import csv
# 保存到csv文件当中 列表里面 [{城市:xxx,温度:7},{}....]
titles = ('city','temp')

def pares_page(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36'
    }
    response = requests.get(url,headers=headers)
    # print(response.content.decode('utf-8'))
    text = response.content.decode('utf-8')

    # 网页解析
    # 1.先找到整页的 div=conMidtab 标签的数据
    # html5lib来解析网页 pip isntall html5lib,补全网页源代码
    soup = BeautifulSoup(text,'html5lib')
    conMidtab = soup.find('div',class_='conMidtab')

    # 2. 接下来去找每一个省会或者直辖市所对应的table标签
    tables = conMidtab.find_all('table')


    # 定义一个列表 保存最终的数据 [{},{}]
    lst = []

    for table in tables:
        # 3. 找table标签里面的tr标签(需要注意 要把前2个tr过滤掉)
        trs = table.find_all('tr')[2:]
        for index,tr in enumerate(trs): # enumerate() 返回的是 下标所以以及对应的值
            tds = tr.find_all('td')
            city_td = tds[0] # 直辖市/省
            if index == 0:
                city_td = tds[1]

            info = {}
            '''
            从打印的结果发现了如果我们取0的时候 只有省的第一个城市(省会)是不对的。其它的数据都是正确的。改成1的时候只有省会是对的,其它的就都是错误的。
            我们什么情况下 取第一个数据 tds[1] 省会
            '''
            city = list(city_td.stripped_strings)[0] # 城市,*取字符串的套路*
            temp_td = tds[-2]
            temp = list(temp_td.stripped_strings)[0] # 温度

            info['city'] = city
            info['temp'] = temp
            lst.append(info)
            print('city:',city,'temp:',temp)
        # break # 先打印北京的
    return lst


def writeData(lst):
    with open('wather.csv','w',encoding='utf-8',newline='') as file_obj:
        writer = csv.DictWriter(file_obj,titles)
        writer.writeheader()
        writer.writerows(lst)


def main():
    lst = []
    # 目标url 先去搞定一个区域 在去搞定其它的区域
    url = 'http://www.weather.com.cn/textFC/hb.shtml' # 华北
    url = 'http://www.weather.com.cn/textFC/db.shtml' # 东北
    url = 'http://www.weather.com.cn/textFC/gat.shtml' # 港澳台

    urls = ['http://www.weather.com.cn/textFC/hb.shtml','http://www.weather.com.cn/textFC/db.shtml','http://www.weather.com.cn/textFC/gat.shtml']
    for url in urls:

        lst += pares_page(url)

    writeData(lst)

if __name__ == '__main__':
    main()

(4)
问题:爬取 海贼王吧 爬取桌面壁纸
具体步骤(分析页面)
1.我们发现要爬取的数据是图片,那么就只要找到它(每张图片)的src 就可以了
经过分析发现网页源码当中没有我们想要爬取的数据。然后我们确定它是经过ajax加载的数据
一般情况下 ajax请求都在 XHR这个选项(XMLHttpRequest)
通过network 继续找真实的数据接口
即找到真正的目标url
2.解析数据
可以把(response)数据通过json (利用json.cn)转换成Python的数据类型的字典(preview)。 然后通过key-value形式找到 每张图片的url
也可以通过正则(对(response)数据直接进行解析)
代码:

import requests
import re
import time
'''

https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&alt=jview&rn=200&tid=1934517161&pn=1&ps=1&pe=40&info=1&_=1620822548466

https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&alt=jview&rn=200&tid=1934517161&pn=1&ps=40&pe=79&wall_type=h&_=1620823519114

https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&alt=jview&rn=200&tid=1934517161&pn=1&ps=79&pe=118&wall_type=h&_=1620823534332

ps=1 ps=40 ps=79   pe=40 pe=79 pe=118   规律 39

'''
name = 1
for i in range(1,80,39):


    # 目标url
    # url = 'https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&alt=jview&rn=200&tid=1934517161&pn=1&ps=1&pe=40&info=1&_=1620822548466'
    url = 'https://tieba.baidu.com/photo/g/bw/picture/list?kw=%E6%B5%B7%E8%B4%BC%E7%8E%8B&alt=jview&rn=200&tid=1934517161&pn=1&' + '&ps=' + str(i) + '&pe=' + str(39 + i) + '&wall_type=h&_=1620823534332'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36'
    }

    res = requests.get(url,headers=headers)
    # print(res.text)
    # 正则表达式匹配数据
    img_urls = re.findall('"murl":"(.*?)"',res.text)

    for img_url in img_urls:
        img_response = requests.get(img_url)
        # 保存数据
        print('正在下载第%d张图片' % name)
        with open('img/%d.jpg'%name,'wb') as file_obj:
            # time.sleep(0.5)
            file_obj.write(img_response.content)

        name += 1
    time.sleep(1)

(5)
问题:通过selenium登录豆瓣
具体步骤
人怎么做,selenium就怎么做 时刻记住:先定位,再操作

# 登录豆瓣
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
import time

driver = webdriver.Chrome()
driver.get('https://www.douban.com/')
# 切换iframe 灵活变通
'''
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":".nojs"}
iframe作祟
'''
login_frame = driver.find_element_by_xpath('//*[@id="anony-reg-new"]/div/div[1]/iframe')
driver.switch_to.frame(login_frame)

# 切换登录方式 千万不要忘记click()
# 当属性有空格的时候 account-tab-account on 如何解决呢?
# 1.可以选其中的一部分(通过测试),技巧:选较长的一段 2 xpath来定位
driver.find_element_by_class_name('account-tab-account').click()
time.sleep(2)
# 定位账号和密码 并输入内容
driver.find_element_by_id('username').send_keys('xxxxxx')
time.sleep(1)
driver.find_element_by_id('password').send_keys('xxxxxx')
time.sleep(1)
# 点击登录按钮
driver.find_element_by_class_name('btn').click()

(6)
问题:通过selenium获取cookie(条件:自己不久之前已登过)
具体步骤(分析页面)
获取cookies–>解析数据–>测试

from selenium import webdriver
import requests
import time
import json
# 模拟登录自己的QQ空间

# 携带cookie进行模拟 也就是我们先通过正常的途径进行登录此时此刻就可以获得一个cookie.然后在正常的编写一个 模拟登录的逻辑就可以啦
# 下面的逻辑 1 要通过selenium获取 qq空间的cookie值 2 解析这个cookie值 3 进行测试

#要通过selenium获取 qq空间的cookie值
#把逻辑封装一下 类 方法
driver = webdriver.Chrome()
# 不要删参数  加载第三方的登录方式
driver.get('https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=%E6%89%8B%E6%9C%BAQQ%E7%A9%BA%E9%97%B4&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=https%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html&pt_no_auth=0')
time.sleep(1)
button = driver.find_element_by_class_name('face')
button.click()
time.sleep(2)
listCookies = driver.get_cookies() # 是python中的list json.loads()
# # 以下的逻辑可以不写 不实现  目的是保存listCookies,方便后续调用
# jsonCookies = json.dumps(listCookies) # 把python的数据类型转换成json类型的字符串(str)
# print(type(jsonCookies),jsonCookies)
#
# with open('qqzone.json','w') as file_obj:
#     file_obj.write(jsonCookies)


# 解析cookie数据 列表推导式 [] 返回的结果是一个新的列表
cookie = [item['name'] + '=' + item['value'] for item in listCookies]
cookie_str = '; '.join(cookie)
#item for item in cookie
print(cookie_str)


# 测试代码 selenium获取和解析之后的cookie是否可以使用
url = 'https://user.qzone.qq.com/2023203294'
headers = {
    'cookie':cookie_str,
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
}

html = requests.get(url,headers=headers)
time.sleep(2)
with open('qzong.html','w',encoding='utf-8') as file_obj:
    file_obj.write(html.text)
print(html.text)

方法总结:

  • requests 获取URL响应
  • selenium 登陆及操作网页(including:输入框、按钮、下拉框、获取cookie)
  • 三种方法解析html(正则、xpath、bs4)
    实施过的案例种类:爬取天气,保存csv;豆瓣top250电影信息,保存csv;爬取图片,并保存

案例总结:(写代码之前,须对网页检查有充分理解)
1》获取html–>并解析->后保存

  • 明确目标URL(注意对ajax处理)
  • 得html
  • 解析(三种)(先整体,后局部)
  • 保存,注意格式

2》登陆网页,获取cookie
用selenium(requests麻烦且难)

(7)
问题:使用selenium获取猫眼电影top100电影信息 [电影排名 电影名称 主演 上映时间 评分]
分析页面结构 选择合适的技术点
1>明确目标的url https://maoyan.com/board/4
2>我们先搞定一页的电影数据 再去搞定其它页的
3>通过分析 数据都是在dl标签里面 dl标签里面每一个dd标签它就是一部电影
细节:
1》翻页的处理

  • 当我们点击到最后一页的时候 发现下一页的按钮没有了 就可以判断是最后一页了

2》报错的处理

from selenium import webdriver
import csv

# # 创建chrome设置对象 程序没有问题在去设置 无界面模式
# options = webdriver.ChromeOptions()
# # 设置无界面功能  --headless 浏览器无界面  --xxxx
# options.add_argument('--headless')
# #selenium获取猫眼电影top100电影信息
driver = webdriver.Chrome()
driver.get('https://maoyan.com/board/4')


def get_one_page():
    # 找到这一页的dd标签 千万不要忘记写dd
    dd_lst = driver.find_elements_by_xpath('//*[@id="app"]/div/div/div[1]/dl/dd')
    single_list = []
    for dd in dd_lst:
        # text属性 获取当前dd节点的子子孙孙的文本内容
        # 视情况而分析 验证我们打印的内容有什么规律吗?如果有 就进一步操作
        # print(dd.text)   #str类型   要测试其结果是啥
        # print('*'*80)
        one_film_info_lst = dd.text.split('\n')
        item = {}
        try:
            item['rank'] = one_film_info_lst[0].strip()
            item['name'] = one_film_info_lst[1].strip()
            item['actor'] = one_film_info_lst[2].strip()
            item['time'] = one_film_info_lst[3].strip()
            item['score'] = one_film_info_lst[4].strip()
        except:
            pass
        single_list.append(item)
        print(item)

    return single_list


all_list = []
while True:

    single_list = get_one_page()

    # if 不是最后一页:
    #     driver.find_element_by_link_text('下一页').click()
    # else:
    #     driver.quit()
    #     break

    all_list += single_list
    try:
        # 找不到最后一页 就会抛出异常 此时就证明是最后一页了
        driver.find_element_by_link_text('下一页').click()
    except Exception as e:
        driver.quit()
        break

with open('maoyetop100.csv', 'w', encoding='utf-8', newline='') as file_obj:
    dictwriter = csv.DictWriter(file_obj, fieldnames=['rank', 'name', 'actor', 'time', 'score'])
    dictwriter.writeheader()
    dictwriter.writerows(all_list)

(8)
需求:selenium爬取京东某商品数据
分析页面结构 选择合适的技术点
1>我们发现 所有的数据都是在一个ul标签 ul标签下面每一个li标签对应的就是一本书。
2>我们拖动 拖动条(滚轮)的时候 页面又加载了数据
代码中 当我们进入这个页面的时候,把这个拖动条拖动一下,拖到最下面,然后等它加载一会儿,等页面元素加载完了之后,我们再去抓取
如何拖动 拖动条?(我们会用到一个 加载js的方法)

细节:
1》翻页的处理

  • 当我们点击到最后一页的时候 发现下一页的按钮还有 要用find()方法

2》如何拖动 拖动条

3》报错的处理


from selenium import webdriver
import time
class JdSpider():
    def __init__(self):
        # 设置无界面
        self.options = webdriver.ChromeOptions()
        # 设置无界面功能  --headless 浏览器无界面  --xxxx
        self.options.add_argument('--headless')
        self.driver = webdriver.Chrome(options=self.options)
        self.driver.get('https://www.jd.com/')
        # 定位输入框和按钮
        self.driver.find_element_by_xpath('//*[@id="key"]').send_keys('爬虫书')
        time.sleep(1)
        self.driver.find_element_by_xpath('//*[@id="search"]/div/div[2]/button').click()
        time.sleep(1)


    def pares_html(self):

        # 进入这个页面的时候,把这个拖动条拖动一下,拖到最下面
        # 0 是从去起始位置开始  document.body.scrollHeight 整个窗口的高度  模板!
        self.driver.execute_script(
            'window.scrollTo(0,document.body.scrollHeight)'
        )

        time.sleep(2)

        # 提取数据 千万不要忘记写li
        li_lst = self.driver.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li')
        for li in li_lst:
            # print(li.text)
            # print('*'*50)
            try:
                item = {}
                item['price'] = li.find_element_by_xpath('.//div[@class="p-price"]/strong').text.strip()
                item['name'] = li.find_element_by_xpath('.//div[@class="p-name"]/a/em').text.strip()
                item['commit'] = li.find_element_by_xpath('.//div[@class="p-commit"]/strong').text.strip()
                item['shop'] = li.find_element_by_xpath('.//div[@class="p-shopnum"]/a').text.strip()
                print(item)
            except Exception as e:
                print(e)


    def main(self):
        while True:
            self.pares_html()
            #
            if self.driver.page_source.find('pn-next disable') == -1:
                self.driver.find_element_by_xpath('//*[@id="J_bottomPage"]/span[1]/a[9]').click()
                time.sleep(1)
            else:
                self.driver.quit()
                break



if __name__ == '__main__':
    spider = JdSpider()
    spider.main()

(9)
需求:获取12306购票订单
具体步骤(分析网页,选择合适的技术点)
1 登录 2 车次以及余票查询 3 解析车次列表 4 确认乘客信息及席别 5 核对信息
经验总结:

  • 字典的操作不太了解
  • 老师的代码没有真正理解,就去码了,导致中途一度停止
  • 运行前,保证代码没有明显错误(没有红线等)
  • 特别注意有许多缩进的地方,(for try if)
  • 一开始码的时候,分析页面(具体步骤) 一定要明确

预定车票的标准:根据车次,然后是否是二等或一等(二等优先级高)
选择席别的标准:二等或一等(二等优先级高)

  • selenium定位时 (属性 元素)
  • 显式等待那里EC的方法 (url 属性值 元素)
#爬取12306订单
import csv
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
#驱动器须定义在类的外面,因为python的垃圾回收机制
driver=webdriver.Chrome()

class spider(object):

    def __init__(self,from_station,to_station,travel_date,train_rank,passengers):#train_rank={'G106':['M','O']}
        self.login_url='https://kyfw.12306.cn/otn/resources/login.html'
        self.personer_url='https://kyfw.12306.cn/otn/view/index.html'
        self.spider_url='https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
        self.confirm_url='https://kyfw.12306.cn/otn/confirmPassenger/initDc'
        self.to_station=to_station
        self.from_station=from_station
        self.travel_date=travel_date
        self.travel_rank=train_rank
        self.passengers=passengers
        self.reader_dict={}
        self.__init__csv()#一开始码的时候,这行代码没写
        self.number=None
        #需要在整个class中调用的属性,先在这里声明

     #初始化城市代号
    def __init__csv(self):
        with open('stations.csv','r',encoding='utf-8') as file_obj:
            readers=csv.DictReader(file_obj)
            for reader in readers:
                name=reader['name']
                code=reader['code']
                self.reader_dict[name]=code

    #登录
    def login(self):
        driver.get(self.login_url)

        WebDriverWait(driver,100).until(
            EC.url_contains(self.personer_url)
        )
        print('登录成功!')


    def spider_analyse(self):
        driver.get(self.spider_url)
        driver.implicitly_wait(3)
        driver.find_element_by_id('gb_closeDefaultWarningWindowDialog_id').click()

        #设置出发地
        fromTag=driver.find_element_by_id('fromStation')
        code=self.reader_dict[self.from_station]
        driver.execute_script('arguments[0].value="%s"'%code,fromTag)
        #设置目的地
        toTag = driver.find_element_by_id('toStation')
        code = self.reader_dict[self.to_station]
        driver.execute_script('arguments[0].value="%s"' % code, toTag)
        #设置日期
        date=driver.find_element_by_id('train_date')
        driver.execute_script('arguments[0].value="%s"' % self.travel_date, date)
        #点击查询
        time.sleep(3)
        query=driver.find_element_by_xpath('//*[@id="query_ticket"]')
        driver.execute_script('arguments[0].click()',query)

        WebDriverWait(driver,10).until(
            EC.presence_of_element_located((By.XPATH,'//tbody[@id="queryLeftTable"]/tr'))
        )
        trains_list=driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')#定位属性不是datatran的tr标签
        is_searched=False
        for i in trains_list:
            try:
                train_list=i.text.replace('\n',' ').split(' ')
                # print(train_list)
                # print('*'*20)
                num=train_list[0]

                if num in self.travel_rank:#判断车次是否在self.travel_rank中
                    # for rank in self.travel_rank[num]:
                    #     if rank=='O':
                    #         pd=train_list[10]
                    #         if pd =='有' or pd.isdigit():
                    #                 is_searched=True
                    #                 break
                    #     if rank=='M':
                    #         pd=train_list[9]
                    #         if pd =='有' or pd.isdigit():
                    #             is_searched=True
                    #             break
                    #关键就是这里的解析部分,代码出错集中在这里
                    pd1=train_list[10]
                    pd2=train_list[9]
                    if pd1=='有' or pd1.isdigit() or pd2=='有' or pd2.isdigit():
                        is_searched=True

                    if is_searched:
                        time.sleep(2)
                        self.number=num
                        order_btn = i.find_element_by_xpath('//*[@id="ticket_5l0000G106B2_01_10"]/td[13]/a')
                        order_btn.click()
            except:
                pass

    def confirm_information(self):
        WebDriverWait(driver,100).until(
            EC.url_contains(self.confirm_url)
        )

        #确认乘客
        labels=driver.find_elements_by_xpath('//ul[@id="normal_passenger_id"]/li/label')
        for label in labels:
            name=label.text
            if name in self.passengers:
                label.click()

        #确认席别
        select=Select(driver.find_element_by_id('seatType_1'))
        for i in self.travel_rank[self.number]:
            try:
                select.select_by_value(i)
            except NoSuchElementException:#可能select.select_by_value(i)找不到
                continue
            else:
                break
        submit_btn = driver.find_element_by_xpath('//*[@id="submitOrder_id"]')
        submit_btn.click()

    # 封装了基本的功能
    def run(self):
        # 登录
        self.login()
        # 车次以及余票查询并解析
        self.spider_analyse()
        # 确认乘客信息
        self.confirm_information()



def main():
    result=spider('上海','北京','2021-05-24',{'G106':['O','M']},['name1','name2'])
    result.run()


if __name__ == '__main__':
    main()

(10)
需求: 爬取古诗文网站中的 诗词的 标题 作者 朝代 诗句 以及翻页 并保存
页面分析:
域名:[‘gushiwen.org’, ‘gushiwen.cn’]
每一首诗都在class="sons"里
1.爬虫程序

import scrapy
from poems.items import PoemsItem

class PoemSpider(scrapy.Spider):
    name = 'poem'
    allowed_domains = ['gushiwen.org','gushiwen.cn']
    start_urls = ['https://www.gushiwen.org/default_1.aspx']

    def parse(self, response):

        div_list=response.xpath('//div[@class="sons"]/div[@class="cont"]')

        for div in div_list:
            name=div.xpath('.//b/text()').get()
            # print(name)
            source=div.xpath('.//p[@class="source"]/a/text()').getall()
            try:
                author=source[0]
                dynasty=source[1]
                content=div.xpath('.//div[@class="contson"]/text()').getall()
                # print(content)
                result=''.join(content).strip()
                # print(result)

                item = PoemsItem(name=name,author=author,dynasty=dynasty,result=result)
                yield item


            except:
                print(name)

        #翻页处理:
        next_href = response.xpath('//a[@id="amore"]/@href').get()
        # 翻页
        if next_href:
            next_url = response.urljoin(next_href)  # urljoin()可以进行url地址的补全
            # request = scrapy.Request(next_url)
            # yield request
            yield scrapy.Request(
                url=next_url,
                callback=self.parse  # 如果这个逻辑是这个parse 就可以省略
            )

2.piplines

import json
class PoemsPipeline:
    def open_spider(self, spider):
        self.fp = open('ancient_poems.txt', 'w', encoding='utf-8')

    def process_item(self, item, spider):
        # 这个Item从爬虫文件过来的时候不是一个字典对象。它是通过PoemsItem()实例化出来的对象
        item_json = json.dumps(dict(item), ensure_ascii=False)  # 输出中文
        self.fp.write(item_json + '\n')
        # print(item)
        return item

    def close_spider(self, spider):
        self.fp.close()

(11)
需求:爬取腾讯招聘网职位及对应职责
页面分析:
1.是否为静态—>动态(ajax)
2.翻页 在scrapy中:1>列出几个URL,然后.format 2>直接找下一页的Url地址 最后 yield scrapy.Request(url,callback=None)
3.实现 (爬虫程序、items、piplines.py)
注:若需要点击跳转到另一个URL 这时看看检查里是否有现成的、找规律
检查、response、preview、网页源代码、json

import scrapy
import json
from recruit.items import RecruitItem
class PositionSpider(scrapy.Spider):
    name = 'position'
    allowed_domains = ['tencent.com']
    first_url='https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1622635924738&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
    second_url='https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1622637678428&postId={}&language=zh-cn'
    start_urls = [first_url.format(1)]

    def parse(self, response):
        # 解析数据 re xpath bs4..
        # response.encoding='utf-8'
        data = json.loads(response.text)
        for job in data['Data']['Posts']:
            item = RecruitItem()
            item['job_name'] = job['RecruitPostName']
            post_id = job['PostId']
            # 获取详情页的url
            detail_url = self.second_url.format(post_id)
            #对每一个职位,再次请求url获取职位
            yield scrapy.Request(
                url=detail_url,
                callback=self.detail_content,
                meta={'item':item}
            )
            # print(item)

        # 翻页
        for page in range(2,3):
            url = self.first_url.format(page)
            yield scrapy.Request(url=url)

    def detail_content(self,response):
        # 数据有没有过来
        # item = response.meta['item']
        item = response.meta.get('item')
        data = json.loads(response.text)
        item['job_duty'] = data['Data']['Responsibility']
        print(item)

(12)
古诗文代码的扩展(进一步爬取每一首古诗的译文与注释)
poem.py

import scrapy
from poems.items import PoemsItem
import re
from lxml import etree
import requests
import time

class PoemSpider(scrapy.Spider):
    name = 'poem'
    allowed_domains = ['gushiwen.org','gushiwen.cn']
    start_urls = ['https://www.gushiwen.org/default_1.aspx']

    def parse(self, response):

        gsw_divs=response.xpath('//div[@class="sons"]/div[@class="cont"]')

        # 过滤非正常诗文,并得取诗文详细内容链接
        if gsw_divs:
            for gsw_div in gsw_divs:
                # time.sleep(0.1)
                if gsw_div.xpath('./div[@class="yizhu"]'):
                    href = gsw_div.xpath('./p/a/@href').get()
                    href_url = response.urljoin(href)
                    yield scrapy.Request(url=href_url, callback=self.parse_1)

        #翻页处理:
        # next_href = response.xpath('//a[@id="amore"]/@href').get()
        # # 翻页
        # if next_href:
        #     next_url = response.urljoin(next_href)  # urljoin()可以进行url地址的补全
        #     # request = scrapy.Request(next_url)
        #     # yield request
        #     yield scrapy.Request(
        #         url=next_url,
        #         callback=self.parse  # 如果这个逻辑是这个parse 就可以省略
        #     )
    #这里的response进入到详细页了
    def parse_1(self,response):
        #获取四项:名称...
        html_text = response.xpath('//div[@id="sonsyuanwen"][1]/div[@class="cont"]')
        title = html_text.xpath('./h1/text()').get()
        author = html_text.xpath('./p[@class="source"]/a[1]/text()').get()
        dynasty = html_text.xpath('./p[@class="source"]/a[2]/text()').get()
        content_list = html_text.xpath('./div[@class="contson"]//text()').getall()
        content = ''.join(content_list).strip()

        #取得“展开阅读全文”链接,如果有则得取ajax页的译文和注释,没有则提取本页上的译文和注释
        pd=response.xpath('//a[@style="text-decoration:none;"]/@href').get()
        #'//div[@style="text-align:center; margin-top:-5px;"]/a/@href'
        if pd:
            # try:
                ID=re.match(r"javascript:.*?,'(.*?)'",str(pd)).group(1)
                # print(type(ID))
                base_url='https://so.gushiwen.cn/nocdn/ajaxfanyi.aspx?id={}'
                parse_html = etree.HTML(requests.get(base_url.format(ID)).text)
                # print(parse_html)
                html_fanyi= parse_html.xpath('//div[@class="contyishang"]//text()')
                # print(html_fanyi)  测试用
                # print('*'*10)
                
            # except:
            #     pass
        else:
            html_fanyi = response.xpath(
                '//div[@class="left"]/div[@class="sons"][2]/div[@class="contyishang"]//text()').getall()
            # print(html_fanyi)

        html_fanyi = ''.join(html_fanyi).replace('\n', '').replace('译文及注释', '').replace('译文', '').replace('注释', '|')

        if html_fanyi:
            fanyi = html_fanyi.split('|')
            translation = fanyi[0]
            notes = fanyi[1]
        else:
            translation = ''
            notes = ''

        item = PoemsItem(title=title,
                       author=author,
                       dynasty=dynasty,
                       content=content,
                       translation=translation,
                       notes=notes)
        yield item

总结:

  • URL一定要正确,一般scrapy不会出现乱码 如果出现了settings.py文件中加个配置项 FEED_EXPORT_ENCODING = 'utf-8
  • 爬到好多空列表—很可能 xpath(就是爬取数据是否正确) 、解析是否正确、反爬、要登录

(13)
需求:爬取汽车之家图片
第一步 页面分析
https://car.autohome.com.cn/photolist/series/48114/6381346.html#pvareaid=3454450

https://car.autohome.com.cn/photolist/series/18/p2/ 第二页
https://car.autohome.com.cn/photolist/series/18/p3/ 第三页

每一个图片地址在//ul[@id=“imgList”]/li ./a/img/@src中

第二步 实现步骤

所有的图片在’//ul[@id=“imgList”]/li’中,一个在 './a/img/@src’中 可能会编辑items.py
piplines.py保存(两种方式)
根据以上操作,记得编辑settings.py文件
middlewares.py编辑
代码 D:\python_spider\基于Scrapy\pic1\audi
第一种方式(指保存方式的不同)
1.audi_spider.py

lass AudiSpiderSpider(scrapy.Spider):
    name = 'audi_spider'
    allowed_domains = ['car.autohome.com.cn']
    start_urls = ['https://car.autohome.com.cn/photolist/series/18/p2/']
    def parse(self, response):
        lis = response.xpath('//ul[@id="imgList"]/li')
        for li in lis:
            # item = {}
            item = AudiItem()
            # 方式一
            # item['src'] = 'https:' + li.xpath('./a/img/@src').extract_first()
            # yield item

2.piplines.py

import os
from scrapy.pipelines.images import ImagesPipeline

class AudiPipeline:
    def process_item(self, item, spider):
        # 获取图片的url
        src = item['src']
        # 获取图片的名字
        img_name = item['src'].split("__")[-1]
        
        # 动态的添加这个路径(目录)
        file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images')
        print(img_name)
        # request.urlretrieve专门用来保存二进制文件
        request.urlretrieve(src, file_path + '/' + img_name)
        return item

3.settings.py

ITEM_PIPELINES = {
   'audi.pipelines.AudiPipeline': 300,
     # 'scrapy.pipelines.images.ImagesPipeline':1   #固定写法
}

第二种方式
1.audi_spider.py

item['image_urls']=['https:' + li.xpath('./a/img/@src').extract_first()]
            yield item

2.items.py

image_urls=scrapy.Field()  #image_urls不能改

3.piplines.py不需编辑
4.settings.py

ITEM_PIPELINES = {
   # 'audi.pipelines.AudiPipeline': 300,
      'scrapy.pipelines.images.ImagesPipeline':1   #固定写法
}

import os
IMAGES_STORE = os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')   #IMAGES_STORE不能改

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

笔记本IT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值