爬取HKSTP入驻企业的信息

要求:

HKSTP企业目录:点进该网址查看HKSTP入驻的每一个公司并获取企业的信息,包括企业名称/邮箱/网址/电话/联系人/公司介绍

企业目录页面:
在这里插入图片描述

企业信息页面:
在这里插入图片描述

第一步 导入相关模块

这里要注意一开始我直接通过from lxml import etree 会有报错,
网上查了下似乎从python3.5开始就无法直接导入etree模块了
解决方法是先引入html模块,通过html模块引入etree

import requests
from lxml import html
import re
import pandas as pd

url='https://www.hkstp.org/en/reach-us/company-directory/?i=&t=All&c=-1&s=-1&s=-1&k=&page=1'
    response = requests.get(url,headers=headers).text
    etree = html.etree
    htmldiv =etree.HTML(response)

第二步 解析企业目录源代码

分析企业目录页面,找到link到企业信息页面的链接,

如下图单个企业信息页面的链接在 DIV[id=“companyList”]/ul/li/div/div/a 标签中的href属性中,

在这里插入图片描述
用xpath解析获得企业的链接,但是这个链接是不完整的,还要拼接一下

link = htmldiv.xpath('//*[@id="companyList"]/ul/li/div/div/a/@href'
url2='https://www.hkstp.org' +  str(link[0])


第三步 解析企业信息页面

企业信息都在class="content-sub-title"的h1标签下,但是这里我遇到了几个挺头疼的问题
1)我们只想抓取企业名称/邮箱/公司网址/电话/联系人/公司介绍 这几个类别,但是Info-list里还包括企业logo,地址,产品等信息
2)即使在我们想要抓取的企业名称/邮箱/网址/电话/联系人/公司介绍 这几个分类里,除了企业名称是每一页里都有的,其他几个分类并不是每个公司都有的,而且邮箱和网址是在标签的属性里,电话,公司介绍这些是在标签的文本里

所以怎么用XPATH做筛选呢?这是身为爬虫小白的我还没有掌握的!
在这里插入图片描述

第四步 正则表达式曲线救国

我想到的解决办法是用正则表达式分别抓取需要的类别,然后分别保存在对应的list中,
这样会有 公司名称/电话/邮箱/网址/联系人/公司介绍 6个列表,每个列表中的元素都是一个元组(公司名称,类别信息),比如电话号码的列表就是 [(公司名称1,电话1)(公司名称2,电话2)],公司名称是作为关键字在最后要把6个列表用merge方法combine到一起的;如果某个公司的某个类别信息缺失,比如没有邮箱,那这个邮箱list中就不会有这个公司名称,最后combine的时候就会以空值代替(merge方法类似于vlookup)

name_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>')
name = name_pattern.findall(response2)
name_list.extend(name)

tel_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Tel[\s\S]*?<p>(.*?)</p>')
tel = tel_pattern.findall(response2)
tel_list.extend(tel)

email_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Email[\s\S]*?mailto:(.*?)"')
mail = email_pattern.findall(response2)
mail_list.extend(mail)

web_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Website[\s\S]*?href="(.*?)"')
web = web_pattern.findall(response2)
web_list.extend(web)

Contact_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Contact Person[\s\S]*?<p>(.*?)</p>')
contact = Contact_pattern.findall(response2)
person_list.extend(contact)

intro_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Introduction[\s\S]*?<p>([\s\S]*?)</p>')
intro = intro_pattern.findall(response2)
intro_list.extend(intro)

第五步 通过pandas 整合

这里我又遇到一个蛋疼的问题,就是我有6个list,而merge方法一次只能匹配两张表?所以我蛋疼的匹配了5次(如果有大神知道更简单的方法请务必告诉我,我查了下conact方法暂时也没找到合适的解决方法)

name_df = pd.DataFrame(name_list, columns=['name'])
tel_df = pd.DataFrame(tel_list,columns=['name','tel_no'])
mail_df = pd.DataFrame(mail_list, columns=['name', 'mail'])
web_df = pd.DataFrame(web_list, columns=['name', 'web'])
person_df = pd.DataFrame(person_list, columns=['name', 'contact_person'])
intro_df = pd.DataFrame(intro_list,columns=['name','Introduction'])

result=pd.merge(name_df,tel_df,on='name',how='left')
result1=pd.merge(result,mail_df,on='name',how='left')
result2=pd.merge(result1,web_df,on='name',how='left')
result3=pd.merge(result2,person_df,on='name',how='left')
result4=pd.merge(result3,intro_df,on='name',how='left')
result4.to_excel('HKSTP.xlsx')

这样基本上就完成啦!

附完整代码:

import requests
from lxml import html
import re
import pandas as pd
import time
from lxml import etree
start=time.time()
headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36'}
name_list =[]
tel_list = []
mail_list = []
web_list = []
person_list = []
intro_list = []
for n in range(1,48):
    print('正在爬去第{}页'.format(n))
    print(time.strftime("%H:%M:%S", time.localtime(time.time())))
    url='https://www.hkstp.org/en/reach-us/company-directory/?i=&t=All&c=-1&s=-1&s=-1&k=&page={}'.format(n)
    response = requests.get(url,headers=headers).text
    etree = html.etree
    htmldiv =etree.HTML(response)
    for i in range(1,21):
        link = htmldiv.xpath('//*[@id="companyList"]/ul/li[{}]/div/div/a/@href'.format(i))
        url2='https://www.hkstp.org' +  str(link[0])
        response2 = requests.get(url2,headers).text

        name_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>')
        name = name_pattern.findall(response2)
        name_list.extend(name)

        tel_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Tel[\s\S]*?<p>(.*?)</p>')
        tel = tel_pattern.findall(response2)
        tel_list.extend(tel)

        email_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Email[\s\S]*?mailto:(.*?)"')
        mail = email_pattern.findall(response2)
        mail_list.extend(mail)

        web_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Website[\s\S]*?href="(.*?)"')
        web = web_pattern.findall(response2)
        web_list.extend(web)

        Contact_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Contact Person[\s\S]*?<p>(.*?)</p>')
        contact = Contact_pattern.findall(response2)
        person_list.extend(contact)

        intro_pattern = re.compile(r'content-sub-title">(.*?)\s*?</h1>[\s\S]*?Introduction[\s\S]*?<p>([\s\S]*?)</p>')
        intro = intro_pattern.findall(response2)
        intro_list.extend(intro)
    time.sleep(4)

name_df = pd.DataFrame(name_list, columns=['name'])
tel_df = pd.DataFrame(tel_list,columns=['name','tel_no'])
mail_df = pd.DataFrame(mail_list, columns=['name', 'mail'])
web_df = pd.DataFrame(web_list, columns=['name', 'web'])
person_df = pd.DataFrame(person_list, columns=['name', 'contact_person'])
intro_df = pd.DataFrame(intro_list,columns=['name','Introduction'])

result=pd.merge(name_df,tel_df,on='name',how='left')
result1=pd.merge(result,mail_df,on='name',how='left')
result2=pd.merge(result1,web_df,on='name',how='left')
result3=pd.merge(result2,person_df,on='name',how='left')
result4=pd.merge(result3,intro_df,on='name',how='left')
pd.set_option('display.max_columns', None)
result4.to_excel('HKSTP.xlsx')
end=time.time()
print("Running time: %s seconds"%(end - start))

问题&待改进

Q1.在批量爬取的时候遇到了HKSTP的反爬措施,导致IP被封了,尝试了IP代理设置仍然没有用,后来换了一个网络环境并设置了4s的翻页间隔才爬取成功。后续要研究如何绕开反爬措施

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


Q2. 有没有更简便的方法不用正则表达式,用Xpath筛选要爬取的内容 ?




Q3:pandas有没有方法可以一次合并多张dataframe?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值