最近收到一个运营朋友的需求,她工作需要采集阿里巴巴国际站的供应商数据。虽然本人只是擅长android开发,python只会皮毛,本着玩一玩的心态,于是这个需求正式立项、着手学习开发,花了三天的时间,也把想要的脚本写出来,于是分享下(分享出来不知道阿里啥时候进行爬虫屏蔽,在此脚本发布时脚本还可执行),不多说,下图就是脚本的执行结果
首先工作,环境搭建(跳过)
其次阿里巴巴国际账号准备(跳过)
然后就是天猫国际站的网页研究和python脚本的编写了
声明浏览器类,浏览器声明
def __init__(self):
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
NoImage = {"profile.managed_default_content_settings.images": 2} # 控制 没有图片
option.add_experimental_option("prefs", NoImage)
# option.add_argument(f'user-agent={ua.chrome}') # 增加浏览器头部
# chrome_options.add_argument(f"--proxy-server=http://{self.ip}") # 增加IP地址。。
# option.add_argument('--headless') #无头模式 不弹出浏览器
self.browser = webdriver.Chrome(executable_path="./chromedriver", options=option)
self.browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined})'
}) #去掉selenium的驱动设置
self.browser.set_window_size(1200,768)
self.wait = WebDriverWait(self.browser, 12)
登陆处理
打开登陆界面,f12打开开发者工具,获取对应的元素元素
对照上图,点击1的按钮进入选中状态,接着鼠标选中登陆的输入框,右侧定位到对应的源码标签区域,也就是3的步骤,然后右击选中copy,进而选择copy xpath。得到这个值即可在python里面通过此值获取相应的标签,然后调用对应的操作,比如sendkey()就是对此标签进行赋值(下面的value值填写的就是由上面3步骤复制到的值)
self.browser.find_element(by=By.XPATH, value='//*[ @ id = "fm-login-id"]').send_keys(user_name)
然后同理得到密码输入框
self.browser.find_element(by=By.XPATH, value='//*[@id="fm-login-password"]').send_keys(pass_word)
表单值输入完成,就是代码模拟点击登陆按钮进行登录操作(click()方法)
self.browser.find_element(by=By.XPATH, value='//*[@id="fm-login-submit"]').click()
由此登陆方法就完成了
def get_login(self):
url='https://passport.alibaba.com/icbu_login.htm'
self.browser.get(url)
time.sleep(1)
self.browser.find_element(by=By.XPATH, value='//*[ @ id = "fm-login-id"]').send_keys(user_name)
self.browser.find_element(by=By.XPATH, value='//*[@id="fm-login-password"]').send_keys(pass_word)
self.browser.find_element(by=By.XPATH, value='//*[@id="fm-login-submit"]').click()
time.sleep(2)
接下来就是进入首页进行搜索
你可以在首页进行随便搜索,然后得到搜索链接可以得到一下的搜索结果界面(声明下,本来也打算用接口的方式进行数据爬取,只不过阿里国际站的接口比较复杂,而且供应商的手机和电话的获取,阿里做了一些屏蔽手段处理,所以使用接口的方式不比较花时间。本着快速完成的目的,选择进行网页模拟操作的方式)
https://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&keywords=data line&tab=supplier&viewtype=L&&page=1
得到上面的搜索链接就可以发现,keyword就是对应的搜索关键词,page就是数据的页码,那么可以提取出来两个参数动态配置,则得到
url = "https://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&keywords="+wd+"&tab=supplier&viewtype=L&&page="+str(page)
wd就是咱们动态输入的搜索关键词,page就是对应的页码 既然可以得到连接,那咱就打开相应网页了
#获取判断网页文本的内容:
def index_page(self,page,wd):
"""
抓取索引页
:param page: 页码
"""
print('正在爬取第', page, '页')
url = "https://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&keywords="+wd+"&tab=supplier&viewtype=L&&page="+str(page)
self.browser.get(url) # 打开新的网页标签
# 执行打开新一个标签页。
self.browser.switch_to.window(self.browser.window_handles[-1]) # 此行代码用来定位当前页面窗口
self.buffer() # 网页滑动 成功切换
#等待元素加载出来
time.sleep(1)
self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#root')))
#获取网页的源代码
html = self.browser.page_source
# print("获取到源码: "+html)
然后,实际打开此网页之后,就会发现,还得有几步操作,搜索列表的数据不足以支撑我们需要的供应商的相关数据,至少联系方式无法直接通过此界面获取,需要进入
进入详情界面
然后就能获取到阿里巴巴的信息了,相关获取对应元素和取值的操作我就不重复说了,直接贴代码
def get_products(self, wd, html_text):
"""
提取商品数据
"""
e = etree.HTML(html_text)
item_main = e.xpath('//div[@id="J-items-content"]//div[@class="item-main"]')
item_title = e.xpath('//*[@id="root"]/div/section[3]/div[2]/div[1]/div[1]/div[1]/div[2]/h3/a/text()')
items = e.xpath('//div[@class="factory-card"]')
print('公司数 ', len(items))
for li in items:
company_name = ''.join(li.xpath('.//div[@class="detail-info"]/h3/a/text()')) # 公司名称
company_phone_page = 'https:' + ''.join(li.xpath('.//div[@class="detail-info"]/h3/a/@href')) # 公司电话连接
product = ''.join(li.xpath('.//div[@class="capability-container"]/strong[2]/text()')) # 主要产品
Attrs = li.xpath('.//div[@class="attrs"]//span[@class="ellipsis search"]/text()')
length = len(Attrs)
country = company_name.split(" ")[0]
total_evenue = ''
sell_adress = ''
product_img = ''
product_list = li.xpath('.//div[@class="products"]/a')
for product_tmp in product_list:
product_img_url = 'https:' + ''.join(product_tmp.xpath('.//div/img/@src'))
product_img = ''.join(product_img_url) # 产品图片
# 进入公司主页
self.browser.get(company_phone_page)
company_home = etree.HTML(self.browser.page_source)
try:
self.browser.find_element(by=By.XPATH, value='//div[@class="store"]').click()
time.sleep(1)
company_home = etree.HTML(self.browser.page_source)
except Exception as e:
print("没找到元素")
phone = ''
address = ''
mobilePhone = ''
try:
self.browser.find_element(by=By.XPATH, value='//div[contains(@class,"nav-box")]/div/ul/li[4]/a').click()
time.sleep(1)
# 点击查看电话
self.browser.find_element(by=By.XPATH, value='//div[@class="sens-mask"]/a').click()
time.sleep(1)
self.browser.find_element(by=By.XPATH, value='// *[@id="dialog-footer-2"]/div/button[1]').click()
# 确认按钮,等着加载数据
time.sleep(1)
company_home = etree.HTML(self.browser.page_source)
test = ''.join(company_home.xpath('//*[@id="8914272098"]/div/div/div[2]/div/div[2]/table/tr[2]/th/text()'))
phone = ''.join(company_home.xpath('//div[@class="col-right"]/table/tr[1]/td/text()'))
mobilePhone = ''.join(company_home.xpath('//div[@class="col-right"]/table/tr[2]/td/text()'))
country = ''.join(company_home.xpath('//div[@class="col-right"]/table/tr[3]/td/text()'))
country += '-'.join(company_home.xpath('//div[@class="col-right"]/table/tr[4]/td/text()'))
country += '-'.join(company_home.xpath('//div[@class="col-right"]/table/tr[5]/td/text()'))
# phone = ''.join(re.findall('Telephone:</th><td>(.*?)</td>', self.browser.page_source, re.S))
# mobilePhone = ''.join(re.findall('Mobile Phone:</th><td>(.*?)</td>', self.browser.page_source, re.S))
address = ''.join(company_home.xpath('//div[@class="mod-content"]/div/table/tr[2]/td/text()'))
except Exception as e:
msg = traceback.format_exc()
print("异常:" + msg)
print("该公司没有电话")
all_down = [wd, company_name, company_phone_page, product, country, phone, mobilePhone, address,
total_evenue, sell_adress, product_img]
save_csv(all_down,wd=wd)
print("企业名称:" + company_name, "企业主页:" + company_phone_page, "企业主营产品:" + product, "国家:" + country,
"电话:" + phone, mobilePhone, "地址:" + address, total_evenue,
sell_adress, "产品图片:" + product_img)
然后就是保存数据到csv里面
def save_csv(lise_line,wd):
file = csv.writer(open("./+"+wd+".csv", 'a', newline="", encoding="utf-8"))
file.writerow(lise_line)
在接下来就是爬取数据完,将数据转成exl表
import pandas as pd
import time
from lxml import etree
import csv
def csv_to_xlsx_pd():
csv = pd.read_csv('alibaba_com_img.csv', encoding='utf-8')
csv.to_excel('alibaba_demo.xlsx', sheet_name='data')
if __name__ == '__main__':
csv_to_xlsx_pd()
然后阿里巴巴爬取数据就完成了,en,终究对python代码掌握不是很熟,所以代码不是很优雅,有相关想法可以留言改进!!! 嗯,不晓得这操作有没有封号的风险,目前暂时没发现,不过发现一种可以越过拦截通过接口的方式获取联系方式,有时间再更新上去吧