网页数据爬取初探

Posted 猛龙过江ing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网页数据爬取初探相关的知识,希望对你有一定的参考价值。

满树和娇烂漫红,万枝丹彩灼春融。——(唐)吴融《桃花》

套用朱自清的话来开头吧!“盼望着,盼望着,东风来了,春天的脚步近了。一切都像刚睡醒的样子,欣欣然张开了眼”。时间不知不觉中已经来到了三月,春回大地,万物复苏。俗话说:一年之计在于春,所以还要努力加油呀!

一、我们要做什么

我先提前说好,由于我只是有点兴趣,所以就玩了一下,也没有仔细研究,所以会说的很浅显笼统。什么?你不在乎?没有关系?你就想看我的文章?那好吧,既然这样,那咱们就闲言少叙,正式开始吧!

最近有个需求就是从网页上爬取一些数据。我们选定采购网作为目标网站,设定一些搜索条件,获取符合条件的条目之后将它们的相关信息提取出来。

二、获取条目链接

首先,设定一些条件,在网页上搜索出我们想要的信息条目,结果如下图所示。

之后,我们需要做的就是获取这些搜索结果的链接,并且下载下来。我们采用Excel表格来进行存储,分成两列,第一列写入条目链接,第二列写入条目名称。话不多说,直接上代码,都在代码里。

from selenium import webdriver
from lxml import etree
import csv


def wash(node):  # 处理网页名称
    res = ''
    for term in node.xpath("./node()[self::text() or self::span]"):
        if str(term)[0] != '<':
            res += term
        elif term.tag == 'span':
            res += term.text
    res = res.strip()
    return res


def main(n):
    url = 'http://search.ccgp.gov.cn/bxsearch?searchtype=1&page_index=' + str(
        n) + '&bidSort=0&buyerName=&projectId=&pinMu=2&bidType=5&dbselect=bidx&kw=%E8%A7%84%E5%88%92&start_time=2018%3A01%3A01&end_time=2018%3A12%3A31&timeType=6&displayZone=%E5%B1%B1%E4%B8%9C%E7%9C%81&zoneId=37+not+3702&pppStatus=&agentName='  # 这个地方就是拼凑URL地址,n代表页数
    print(url)
    options = webdriver.FirefoxOptions()
    options.add_argument('-headless')
    browser = webdriver.Firefox(firefox_options=options)
    browser.get(url)
    html_source = browser.page_source
    browser.quit()
    tree = etree.HTML(html_source)
    html_data = tree.xpath('//*[@class="vT-srch-result-list-bid"]/li/a/@href')  # URL地址
    html_text = tree.xpath('//*[@class="vT-srch-result-list-bid"]/li/a')  # 网页名称
    rongqi_text = []

    for k in html_text:
        rongqi_text.append(wash(k))

    h_n = 0
    for i in html_data:
        a = i, rongqi_text[h_n]  # 把地址和网页名称都交给了a
        h_n = h_n + 1
        out = open(link_path, 'a', newline='')
        csv_write = csv.writer(out, dialect='excel')
        csv_write.writerow(a)
        out.close()


link_path = '001.csv'

for a in range(1):  # 有几页就写几
    n = a + 1
    main(n)
    print("当前第" + str(n) + "页。")

其中,浏览器地址栏里的地址需要经过处理之后放到存放地址的那里,完成URL地址的拼凑。这样我们就获取到了满足条件的条目的链接和名称了。

三、获取网页的相关信息

这一步是非常关键的,说简单也简单,但是说难也非常的难,主要还是取决于网页的格式样式以及不同网页之间是否发生了变化。众所周知,计算机处理一些重复性的工作比较拿手,因此当网页的形式不断变化时,计算机很可能会束手无策。话不多说,还是直接上代码。

import csv
from lxml import etree
import pandas as pd


def csv_to_dataframe(csv_path):  # csv转dataframe
    data = pd.read_csv(csv_path, sep=',', engine='python', iterator=True, encoding='ANSI')
    loop = True
    chunkSize = 10000
    chunks = []
    while loop:
        try:
            chunk = data.get_chunk(chunkSize)
            chunk = chunk.dropna(axis=1)
            chunk = chunk.drop_duplicates()
            chunks.append(chunk)
        except StopIteration:
            loop = False
    df = pd.concat(chunks, ignore_index=True)
    df = df.dropna(axis=1)
    df = df.drop_duplicates()
    return df


def get_message(csv_path, save_name):
    df = csv_to_dataframe(csv_path)
    df = df.drop_duplicates("name", keep='first').reset_index(drop=True)
    num = len(df)
    print(num)
    rongqi = []
    for k in range(num):
        url = df.iloc[k, 0]
        print(url)
        page = page[1]
        if page != '':
            tree = etree.HTML(page)
            bianhao1 = tree.xpath('/html/body/div[2]/div/div[2]/div/div[3]/div/p[4]/text()')
            zhongbiaodanwei1 = None
            name = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[2]/td[2]/text()')
            caigoudanwei1 = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[4]/td[2]/text()')
            xingzhengqu = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[5]/td[2]/text()')
            shijian = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[5]/td[4]/text()')
            zhuanjia1 = None
            jine1 = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[7]/td[4]/text()')
            dizhi1 = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[12]/td[2]/text()')
            caigou_lianxifangshi1 = tree.xpath(
                '/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[13]/td[2]/text()')
            daili_name1 = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[14]/td[2]/text()')
            daili_dizhi1 = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[15]/td[2]/text()')
            daili_lianxifangshi1 = tree.xpath('/html/body/div[2]/div/div[2]/div/div[2]/table/tbody/tr[16]/td[2]/text()')
            a = [bianhao1, zhongbiaodanwei1, name, caigoudanwei1, xingzhengqu, shijian, zhuanjia1, jine1, dizhi1,
                 caigou_lianxifangshi1, daili_name1, daili_dizhi1, daili_lianxifangshi1,
                 url]  # 拼凑数据,依次为:项目编号、中标单位、项目名称、采购单位、行政区、时间、评审专家、项目金额、采购单位地址、采购单位联系方式、代理单位名称、代理单位地址、代理单位联系方式、URL地址
        else:
            a = ['网页格式有误', '网页格式有误', '网页格式有误', '网页格式有误', '网页格式有误', '网页格式有误',
                 '网页格式有误', '网页格式有误', '网页格式有误', '网页格式有误',
                 '网页格式有误', '网页格式有误', '网页格式有误', url]

        print(a)
        rongqi.append(a)
        out = open(save_name, 'a', newline='', encoding='gbk')
        try:
            csv_write = csv.writer(out, dialect='excel')
            csv_write.writerow(rongqi[0])

        finally:
            out.close()
            rongqi = []


csv_path = 'link_js.csv'  # 前文生成的存放URL地址的CSV文件
save_name = 'link_result.csv'  # 生成爬取结果的CSV文件
get_message(csv_path, save_name)

代码运行之前,需要在上一步生成的存放链接的CSV文件添加“name”作为首行。再说一下有效信息的提取吧,其他的也没有什么特别的,就提取网页,往CSV里写入数据之类的。网页信息的定位提取方式有多种,其中一种是使用XPath定位,也就是代码中使用的这种方法。打开目标网页,按下F12,就能够获得网页的HTML格式(姑且就这么叫吧),如下图所示。之后就手动数一数,看目标信息在什么位置,然后就可以拼写出来了。当然也可以使用搜索,找到信息之后右键-复制-XPath。还有一种获取地址的方法就是使用“查看器”左边的那个,点击网页中想提取的信息,然后右键-复制-XPath,这种方法没有上一个鲁棒。这两种方法只能保证当前网页是有效的,至于其他的网页,就只能听天由命了。另外还可以通过正则表达式什么的进行信息提取,我目前还没有研究过。

另外,搜索资料看到有人这么进行信息定位,感觉更好一些,不容易出现信息错乱,分享一下。

import requests


def get_detail_page(url):
    try:
        response = requests.get(url)
        if response.status_code == 200:
            html = response.content.decode('utf-8', 'ignore').replace(u'\\xa9', u'')
            return html
    except requests.ConnectionError:
        return None


html = get_detail_page(url)
table_list = html.xpath('//div[@class="table"]//tr')
# print(table_list)
all_info = 
for table in table_list:
    if len(table.xpath('td[@class="title"]/text()')) > 0:
        title = ''.join(table.xpath('td[@class="title"]/text()'))
        value = ''.join(table.xpath('td[@colspan="3"]/text()'))
        if (title.find('附件') == 0):
            value = 'http://www.ccgp.gov.cn/oss/download?uuid=' + ''.join(table.xpath('td[@colspan="3"]/a/@id'))
            # print(title+value)
        if ('公告时间' in title):
            title = '公告时间'
            value = table.xpath('td[@width="168"]/text()')[1]
            district_key = '行政区域'
            district_value = (table.xpath('td[@width="168"]/text()'))[0]
            all_info[district_key] = district_value
        if '本项目招标公告日期中标日期' in title:
            title = '本项目招标公告日期'
            value = table.xpath('td[@width="168"]/text()')[0]
            zhongbiaoriqi_key = '中标日期'
            zhongbiaoriqi_value = table.xpath('td[@width="168"]/text()')[1]
            all_info[zhongbiaoriqi_key] = zhongbiaoriqi_value
            # print('中标日期'+zhongbiaoriqi_value)
        if '本项目招标公告日期成交日期' in title:
            title = '本项目招标公告日期'
            value = table.xpath('td[@width="168"]/text()')[0]
            zhongbiaoriqi_key = '中标日期'
            zhongbiaoriqi_value = ''.join(table.xpath('td[@width="168"]/text()'))[11:]
            # print('zhongbiaoriqi_value:'+zhongbiaoriqi_value)
            all_info[zhongbiaoriqi_key] = zhongbiaoriqi_value
        all_info[title] = value
        all_info['插入时间'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

这样,网页信息爬取的任务就完成了。由于博主第一次接触这方面的东西,难免有疏漏之处,欢迎批评指正。

参考

1、爬虫-政府采购网数据抓取(2018-12-28)

以上是关于网页数据爬取初探的主要内容,如果未能解决你的问题,请参考以下文章

Python爬虫初探 - selenium+beautifulsoup4+chromedriver爬取需要登录的网页信息

scrapy初探之爬取武sir首页博客

python3爬虫初探之从爬取到保存

想用python爬取网页上的图片,但无法用select()方法定位图片的源地址?

怎么用python爬取一个网站的网页数量

爬虫——使用多进程爬取视频数据